Passed
Push — master ( 17818e...190bd7 )
by Yannick
09:25
created

Agenda::editEvent()   F

Complexity

Conditions 46
Paths 8216

Size

Total Lines 320
Code Lines 198

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 46
eloc 198
nc 8216
nop 14
dl 0
loc 320
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
/**
5
 * Class Agenda.
6
 *
7
 * @author: Julio Montoya <[email protected]>
8
 */
9
class Agenda
10
{
11
    public $events = [];
12
    /** @var string Current type */
13
    public $type = 'personal';
14
    public $types = ['personal', 'admin', 'course'];
15
    public $sessionId = 0;
16
    public $senderId;
17
    /** @var array */
18
    public $course;
19
    /** @var string */
20
    public $comment;
21
    public $eventStudentPublicationColor;
22
    /** @var array */
23
    private $sessionInfo;
24
    /** @var bool */
25
    private $isAllowedToEdit;
26
27
    /**
28
     * Constructor.
29
     *
30
     * @param string $type
31
     * @param int    $senderId  Optional The user sender ID
32
     * @param int    $courseId  Optional. The course ID
33
     * @param int    $sessionId Optional The session ID
34
     */
35
    public function __construct(
36
        $type,
37
        $senderId = 0,
38
        $courseId = 0,
39
        $sessionId = 0
40
    ) {
41
        // Table definitions
42
        $this->tbl_global_agenda = Database::get_main_table(TABLE_MAIN_SYSTEM_CALENDAR);
43
        $this->tbl_personal_agenda = Database::get_main_table(TABLE_PERSONAL_AGENDA);
44
        $this->tbl_course_agenda = Database::get_course_table(TABLE_AGENDA);
45
        $this->table_repeat = Database::get_course_table(TABLE_AGENDA_REPEAT);
46
47
        $this->setType($type);
48
        $this->setSenderId($senderId ?: api_get_user_id());
49
        $isAllowToEdit = false;
50
51
        switch ($type) {
52
            case 'course':
53
                $sessionId = $sessionId ?: api_get_session_id();
54
                $sessionInfo = api_get_session_info($sessionId);
55
                $this->setSessionId($sessionId);
56
                $this->setSessionInfo($sessionInfo);
57
58
                // Setting the course object if we are in a course
59
                $courseInfo = api_get_course_info_by_id($courseId);
60
                if (!empty($courseInfo)) {
61
                    $this->set_course($courseInfo);
62
                }
63
64
                // Check if teacher/admin rights.
65
                $isAllowToEdit = api_is_allowed_to_edit(false, true);
66
                // Check course setting.
67
                if (api_get_course_setting('allow_user_edit_agenda') === '1'
68
                    && api_is_allowed_in_course()
69
                ) {
70
                    $isAllowToEdit = true;
71
                }
72
73
                $groupId = api_get_group_id();
74
                if (!empty($groupId)) {
75
                    $groupInfo = GroupManager::get_group_properties($groupId);
76
                    $userHasAccess = GroupManager::user_has_access(
77
                        api_get_user_id(),
78
                        $groupInfo['iid'],
79
                        GroupManager::GROUP_TOOL_CALENDAR
80
                    );
81
                    $isTutor = GroupManager::is_tutor_of_group(
82
                        api_get_user_id(),
83
                        $groupInfo
84
                    );
85
86
                    $isGroupAccess = $userHasAccess || $isTutor;
87
                    $isAllowToEdit = false;
88
                    if ($isGroupAccess) {
89
                        $isAllowToEdit = true;
90
                    }
91
                }
92
93
                if (!empty($sessionId)) {
94
                    $allowDhrToEdit = api_get_configuration_value('allow_agenda_edit_for_hrm');
95
                    if ($allowDhrToEdit) {
96
                        $isHrm = SessionManager::isUserSubscribedAsHRM($sessionId, api_get_user_id());
97
                        if ($isHrm) {
98
                            $isAllowToEdit = true;
99
                        }
100
                    }
101
                }
102
                break;
103
            case 'admin':
104
                $isAllowToEdit = api_is_platform_admin();
105
                break;
106
            case 'personal':
107
                $isAllowToEdit = !api_is_anonymous();
108
                break;
109
        }
110
111
        $this->setIsAllowedToEdit($isAllowToEdit);
112
        $this->events = [];
113
        $agendaColors = array_merge(
114
            [
115
                'platform' => 'red', //red
116
                'course' => '#458B00', //green
117
                'group' => '#A0522D', //siena
118
                'session' => '#00496D', // kind of green
119
                'other_session' => '#999', // kind of green
120
                'personal' => 'steel blue', //steel blue
121
                'student_publication' => '#FF8C00', //DarkOrange
122
            ],
123
            api_get_configuration_value('agenda_colors') ?: []
124
        );
125
126
        // Event colors
127
        $this->event_platform_color = $agendaColors['platform'];
128
        $this->event_course_color = $agendaColors['course'];
129
        $this->event_group_color = $agendaColors['group'];
130
        $this->event_session_color = $agendaColors['session'];
131
        $this->eventOtherSessionColor = $agendaColors['other_session'];
132
        $this->event_personal_color = $agendaColors['personal'];
133
        $this->eventStudentPublicationColor = $agendaColors['student_publication'];
134
    }
135
136
    /**
137
     * @param int $senderId
138
     */
139
    public function setSenderId($senderId)
140
    {
141
        $this->senderId = (int) $senderId;
142
    }
143
144
    /**
145
     * @return int
146
     */
147
    public function getSenderId()
148
    {
149
        return $this->senderId;
150
    }
151
152
    /**
153
     * @param string $type can be 'personal', 'admin'  or  'course'
154
     */
155
    public function setType($type)
156
    {
157
        $typeList = $this->getTypes();
158
        if (in_array($type, $typeList)) {
159
            $this->type = $type;
160
        }
161
    }
162
163
    /**
164
     * Returns the type previously set (and filtered) through setType
165
     * If setType() was not called, then type defaults to "personal" as
166
     * set in the class definition.
167
     */
168
    public function getType()
169
    {
170
        if (isset($this->type)) {
171
            return $this->type;
172
        }
173
    }
174
175
    /**
176
     * @param int $id
177
     */
178
    public function setSessionId($id)
179
    {
180
        $this->sessionId = (int) $id;
181
    }
182
183
    /**
184
     * @param array $sessionInfo
185
     */
186
    public function setSessionInfo($sessionInfo)
187
    {
188
        $this->sessionInfo = $sessionInfo;
189
    }
190
191
    /**
192
     * @return int $id
193
     */
194
    public function getSessionId()
195
    {
196
        return $this->sessionId;
197
    }
198
199
    /**
200
     * @param array $courseInfo
201
     */
202
    public function set_course($courseInfo)
203
    {
204
        $this->course = $courseInfo;
205
    }
206
207
    /**
208
     * @return array
209
     */
210
    public function getTypes()
211
    {
212
        return $this->types;
213
    }
214
215
    /**
216
     * Adds an event to the calendar.
217
     *
218
     * @param string $start                 datetime format: 2012-06-14 09:00:00 in local time
219
     * @param string $end                   datetime format: 2012-06-14 09:00:00 in local time
220
     * @param string $allDay                (true, false)
221
     * @param string $title
222
     * @param string $content
223
     * @param array  $usersToSend           array('everyone') or a list of user/group ids
224
     * @param bool   $addAsAnnouncement     event as a *course* announcement
225
     * @param int    $parentEventId
226
     * @param array  $attachmentArray       array of $_FILES['']
227
     * @param array  $attachmentCommentList
228
     * @param string $eventComment
229
     * @param string $color
230
     *
231
     * @return int
232
     */
233
    public function addEvent(
234
        $start,
235
        $end,
236
        $allDay,
237
        $title,
238
        $content,
239
        $usersToSend = [],
240
        $addAsAnnouncement = false,
241
        $parentEventId = null,
242
        $attachmentArray = [],
243
        $attachmentCommentList = [],
244
        $eventComment = null,
245
        $color = ''
246
    ) {
247
        $start = api_get_utc_datetime($start);
248
        $end = api_get_utc_datetime($end);
249
        $allDay = isset($allDay) && $allDay === 'true' ? 1 : 0;
250
        $id = null;
251
252
        switch ($this->type) {
253
            case 'personal':
254
                $attributes = [
255
                    'user' => api_get_user_id(),
256
                    'title' => $title,
257
                    'text' => $content,
258
                    'date' => $start,
259
                    'enddate' => $end,
260
                    'all_day' => $allDay,
261
                    'color' => $color,
262
                ];
263
264
                $id = Database::insert(
265
                    $this->tbl_personal_agenda,
266
                    $attributes
267
                );
268
                break;
269
            case 'course':
270
                $attributes = [
271
                    'title' => $title,
272
                    'content' => $content,
273
                    'start_date' => $start,
274
                    'end_date' => $end,
275
                    'all_day' => $allDay,
276
                    'session_id' => $this->getSessionId(),
277
                    'c_id' => $this->course['real_id'],
278
                    'comment' => $eventComment,
279
                    'color' => $color,
280
                ];
281
282
                if (!empty($parentEventId)) {
283
                    $attributes['parent_event_id'] = $parentEventId;
284
                }
285
286
                $senderId = $this->getSenderId();
287
                $sessionId = $this->getSessionId();
288
289
                // Simple course event.
290
                $id = Database::insert($this->tbl_course_agenda, $attributes);
291
292
                if ($id) {
293
                    $sql = "UPDATE ".$this->tbl_course_agenda." SET id = iid WHERE iid = $id";
294
                    Database::query($sql);
295
296
                    $groupId = api_get_group_id();
297
                    $groupInfo = [];
298
                    if ($groupId) {
299
                        $groupInfo = GroupManager::get_group_properties(
300
                            $groupId
301
                        );
302
                    }
303
304
                    if (!empty($usersToSend)) {
305
                        $sendTo = $this->parseSendToArray($usersToSend);
306
                        if ($sendTo['everyone']) {
307
                            api_item_property_update(
308
                                $this->course,
309
                                TOOL_CALENDAR_EVENT,
310
                                $id,
311
                                'AgendaAdded',
312
                                $senderId,
313
                                $groupInfo,
314
                                '',
315
                                $start,
316
                                $end,
317
                                $sessionId
318
                            );
319
                            api_item_property_update(
320
                                $this->course,
321
                                TOOL_CALENDAR_EVENT,
322
                                $id,
323
                                'visible',
324
                                $senderId,
325
                                $groupInfo,
326
                                '',
327
                                $start,
328
                                $end,
329
                                $sessionId
330
                            );
331
                        } else {
332
                            // Storing the selected groups
333
                            if (!empty($sendTo['groups'])) {
334
                                foreach ($sendTo['groups'] as $group) {
335
                                    $groupInfoItem = [];
336
                                    if ($group) {
337
                                        $groupInfoItem = GroupManager::get_group_properties($group);
338
                                    }
339
340
                                    api_item_property_update(
341
                                        $this->course,
342
                                        TOOL_CALENDAR_EVENT,
343
                                        $id,
344
                                        'AgendaAdded',
345
                                        $senderId,
346
                                        $groupInfoItem,
347
                                        0,
348
                                        $start,
349
                                        $end,
350
                                        $sessionId
351
                                    );
352
353
                                    api_item_property_update(
354
                                        $this->course,
355
                                        TOOL_CALENDAR_EVENT,
356
                                        $id,
357
                                        'visible',
358
                                        $senderId,
359
                                        $groupInfoItem,
360
                                        0,
361
                                        $start,
362
                                        $end,
363
                                        $sessionId
364
                                    );
365
                                }
366
                            }
367
368
                            // storing the selected users
369
                            if (!empty($sendTo['users'])) {
370
                                foreach ($sendTo['users'] as $userId) {
371
                                    api_item_property_update(
372
                                        $this->course,
373
                                        TOOL_CALENDAR_EVENT,
374
                                        $id,
375
                                        'AgendaAdded',
376
                                        $senderId,
377
                                        $groupInfo,
378
                                        $userId,
379
                                        $start,
380
                                        $end,
381
                                        $sessionId
382
                                    );
383
384
                                    api_item_property_update(
385
                                        $this->course,
386
                                        TOOL_CALENDAR_EVENT,
387
                                        $id,
388
                                        'visible',
389
                                        $senderId,
390
                                        $groupInfo,
391
                                        $userId,
392
                                        $start,
393
                                        $end,
394
                                        $sessionId
395
                                    );
396
                                }
397
                            }
398
                        }
399
                    }
400
401
                    // Add announcement.
402
                    if ($addAsAnnouncement) {
403
                        $this->storeAgendaEventAsAnnouncement(
404
                            $id,
405
                            $usersToSend
406
                        );
407
                    }
408
409
                    // Add attachment.
410
                    if (isset($attachmentArray) && !empty($attachmentArray)) {
411
                        $counter = 0;
412
                        foreach ($attachmentArray as $attachmentItem) {
413
                            $this->addAttachment(
414
                                $id,
415
                                $attachmentItem,
416
                                $attachmentCommentList[$counter],
417
                                $this->course
418
                            );
419
                            $counter++;
420
                        }
421
                    }
422
                }
423
                break;
424
            case 'admin':
425
                if (api_is_platform_admin()) {
426
                    $attributes = [
427
                        'title' => $title,
428
                        'content' => $content,
429
                        'start_date' => $start,
430
                        'end_date' => $end,
431
                        'all_day' => $allDay,
432
                        'access_url_id' => api_get_current_access_url_id(),
433
                    ];
434
435
                    $id = Database::insert(
436
                        $this->tbl_global_agenda,
437
                        $attributes
438
                    );
439
                }
440
                break;
441
        }
442
443
        return $id;
444
    }
445
446
    /**
447
     * @param int $eventId
448
     * @param int $courseId
449
     *
450
     * @return array
451
     */
452
    public function getRepeatedInfoByEvent($eventId, $courseId)
453
    {
454
        $repeatTable = Database::get_course_table(TABLE_AGENDA_REPEAT);
455
        $eventId = (int) $eventId;
456
        $courseId = (int) $courseId;
457
        $sql = "SELECT * FROM $repeatTable
458
                WHERE c_id = $courseId AND cal_id = $eventId";
459
        $res = Database::query($sql);
460
        $repeatInfo = [];
461
        if (Database::num_rows($res) > 0) {
462
            $repeatInfo = Database::fetch_array($res, 'ASSOC');
463
        }
464
465
        return $repeatInfo;
466
    }
467
468
    /**
469
     * @param string $type
470
     * @param string $startEvent      in UTC
471
     * @param string $endEvent        in UTC
472
     * @param string $repeatUntilDate in UTC
473
     *
474
     * @throws Exception
475
     *
476
     * @return array
477
     */
478
    public function generateDatesByType($type, $startEvent, $endEvent, $repeatUntilDate)
479
    {
480
        $continue = true;
481
        $repeatUntilDate = new DateTime($repeatUntilDate, new DateTimeZone('UTC'));
482
        $loopMax = 365;
483
        $counter = 0;
484
        $list = [];
485
486
        switch ($type) {
487
            case 'daily':
488
                $interval = 'P1D';
489
                break;
490
            case 'weekly':
491
                $interval = 'P1W';
492
                break;
493
            case 'monthlyByDate':
494
                $interval = 'P1M';
495
                break;
496
            case 'monthlyByDay':
497
                // not yet implemented
498
                break;
499
            case 'monthlyByDayR':
500
                // not yet implemented
501
                break;
502
            case 'yearly':
503
                $interval = 'P1Y';
504
                break;
505
        }
506
507
        if (empty($interval)) {
508
            return [];
509
        }
510
        $timeZone = api_get_timezone();
511
512
        while ($continue) {
513
            $startDate = new DateTime($startEvent, new DateTimeZone('UTC'));
514
            $endDate = new DateTime($endEvent, new DateTimeZone('UTC'));
515
516
            $startDate->add(new DateInterval($interval));
517
            $endDate->add(new DateInterval($interval));
518
519
            $newStartDate = $startDate->format('Y-m-d H:i:s');
520
            $newEndDate = $endDate->format('Y-m-d H:i:s');
521
522
            $startEvent = $newStartDate;
523
            $endEvent = $newEndDate;
524
525
            if ($endDate > $repeatUntilDate) {
526
                break;
527
            }
528
529
            // @todo remove comment code
530
            $startDateInLocal = new DateTime($newStartDate, new DateTimeZone($timeZone));
531
            //$originalOffset = $startDate->getOffset();
532
            if ($startDateInLocal->format('I') == 0) {
533
                // Is saving time? Then fix UTC time to add time
534
                $seconds = $startDateInLocal->getOffset();
535
                $startDate->add(new DateInterval("PT".$seconds."S"));
536
                $startDateFixed = $startDate->format('Y-m-d H:i:s');
537
                $startDateInLocalFixed = new DateTime($startDateFixed, new DateTimeZone($timeZone));
538
                $newStartDate = $startDateInLocalFixed->format('Y-m-d H:i:s');
539
            } else {
540
                /*$seconds = $startDateInLocal->getOffset();
541
                $startDate->add(new DateInterval("PT".$seconds."S"));
542
                $startDateFixed = $startDate->format('Y-m-d H:i:s');
543
                $startDateInLocalFixed = new DateTime($startDateFixed, new DateTimeZone($timeZone));
544
                $newStartDate = $startDateInLocalFixed->format('Y-m-d H:i:s');*/
545
            }
546
            //var_dump($newStartDate.' - '.$startDateInLocal->format('I'));
547
            $endDateInLocal = new DateTime($newEndDate, new DateTimeZone($timeZone));
548
549
            if ($endDateInLocal->format('I') == 0) {
550
                // Is saving time? Then fix UTC time to add time
551
                $seconds = $endDateInLocal->getOffset();
552
                $endDate->add(new DateInterval("PT".$seconds."S"));
553
                $endDateFixed = $endDate->format('Y-m-d H:i:s');
554
                $endDateInLocalFixed = new DateTime($endDateFixed, new DateTimeZone($timeZone));
555
                $newEndDate = $endDateInLocalFixed->format('Y-m-d H:i:s');
556
            }
557
            $list[] = ['start' => $newStartDate, 'end' => $newEndDate, 'i' => $startDateInLocal->format('I')];
558
            $counter++;
559
560
            // just in case stop if more than $loopMax
561
            if ($counter > $loopMax) {
562
                break;
563
            }
564
        }
565
566
        return $list;
567
    }
568
569
    /**
570
     * @param int    $eventId
571
     * @param string $type
572
     * @param string $end     in UTC
573
     * @param array  $sentTo
574
     *
575
     * @return bool
576
     */
577
    public function addRepeatedItem($eventId, $type, $end, $sentTo = [])
578
    {
579
        $t_agenda = Database::get_course_table(TABLE_AGENDA);
580
        $t_agenda_r = Database::get_course_table(TABLE_AGENDA_REPEAT);
581
582
        if (empty($this->course)) {
583
            return false;
584
        }
585
586
        $courseId = $this->course['real_id'];
587
        $eventId = (int) $eventId;
588
589
        $sql = "SELECT title, content, start_date, end_date, all_day
590
                FROM $t_agenda
591
                WHERE c_id = $courseId AND id = $eventId";
592
        $res = Database::query($sql);
593
594
        if (Database::num_rows($res) !== 1) {
595
            return false;
596
        }
597
598
        $typeList = [
599
            'daily',
600
            'weekly',
601
            'monthlyByDate',
602
            'monthlyByDay',
603
            'monthlyByDayR',
604
            'yearly',
605
        ];
606
607
        if (!in_array($type, $typeList)) {
608
            return false;
609
        }
610
611
        $now = time();
612
613
        // The event has to repeat *in the future*. We don't allow repeated
614
        // events in the past
615
        if ($end > $now) {
616
            return false;
617
        }
618
619
        $row = Database::fetch_array($res);
620
621
        $title = $row['title'];
622
        $content = $row['content'];
623
        $allDay = $row['all_day'];
624
625
        $type = Database::escape_string($type);
626
        $end = Database::escape_string($end);
627
        $endTimeStamp = api_strtotime($end, 'UTC');
628
        $sql = "INSERT INTO $t_agenda_r (c_id, cal_id, cal_type, cal_end)
629
                VALUES ($courseId, '$eventId', '$type', '$endTimeStamp')";
630
        Database::query($sql);
631
632
        $generatedDates = $this->generateDatesByType($type, $row['start_date'], $row['end_date'], $end);
633
634
        if (empty($generatedDates)) {
635
            return false;
636
        }
637
638
        foreach ($generatedDates as $dateInfo) {
639
            $start = api_get_local_time($dateInfo['start']);
640
            $end = api_get_local_time($dateInfo['end']);
641
            $this->addEvent(
642
                $start,
643
                $end,
644
                $allDay,
645
                $title,
646
                $content,
647
                $sentTo,
648
                false,
649
                $eventId
650
            );
651
        }
652
653
        return true;
654
    }
655
656
    /**
657
     * @param int   $item_id
658
     * @param array $sentTo
659
     *
660
     * @return int
661
     */
662
    public function storeAgendaEventAsAnnouncement($item_id, $sentTo = [])
663
    {
664
        $table_agenda = Database::get_course_table(TABLE_AGENDA);
665
        $courseId = api_get_course_int_id();
666
667
        // Check params
668
        if (empty($item_id) || $item_id != strval(intval($item_id))) {
669
            return -1;
670
        }
671
672
        // Get the agenda item.
673
        $item_id = intval($item_id);
674
        $sql = "SELECT * FROM $table_agenda
675
                WHERE c_id = $courseId AND id = ".$item_id;
676
        $res = Database::query($sql);
677
678
        if (Database::num_rows($res) > 0) {
679
            $row = Database::fetch_array($res, 'ASSOC');
680
681
            // Sending announcement
682
            if (!empty($sentTo)) {
683
                $id = AnnouncementManager::add_announcement(
684
                    api_get_course_info(),
685
                    api_get_session_id(),
686
                    $row['title'],
687
                    $row['content'],
688
                    $sentTo,
689
                    null,
690
                    null,
691
                    $row['end_date']
692
                );
693
694
                AnnouncementManager::sendEmail(
695
                    api_get_course_info(),
696
                    api_get_session_id(),
697
                    $id
698
                );
699
700
                return $id;
701
            }
702
        }
703
704
        return -1;
705
    }
706
707
    /**
708
     * Edits an event.
709
     *
710
     * @param int    $id
711
     * @param string $start                 datetime format: 2012-06-14 09:00:00
712
     * @param string $end                   datetime format: 2012-06-14 09:00:00
713
     * @param int    $allDay                is all day 'true' or 'false'
714
     * @param string $title
715
     * @param string $content
716
     * @param array  $usersToSend
717
     * @param array  $attachmentArray
718
     * @param array  $attachmentCommentList
719
     * @param string $comment
720
     * @param string $color
721
     * @param bool   $addAnnouncement
722
     * @param bool   $updateContent
723
     * @param int    $authorId
724
     *
725
     * @return bool
726
     */
727
    public function editEvent(
728
        $id,
729
        $start,
730
        $end,
731
        $allDay,
732
        $title,
733
        $content,
734
        $usersToSend = [],
735
        $attachmentArray = [],
736
        $attachmentCommentList = [],
737
        $comment = null,
738
        $color = '',
739
        $addAnnouncement = false,
740
        $updateContent = true,
741
        $authorId = 0
742
    ) {
743
        $start = api_get_utc_datetime($start);
744
        $end = api_get_utc_datetime($end);
745
        $allDay = isset($allDay) && $allDay == 'true' ? 1 : 0;
746
        $authorId = empty($authorId) ? api_get_user_id() : (int) $authorId;
747
748
        switch ($this->type) {
749
            case 'personal':
750
                $eventInfo = $this->get_event($id);
751
                if ($eventInfo['user'] != api_get_user_id()) {
752
                    break;
753
                }
754
                $attributes = [
755
                    'title' => $title,
756
                    'date' => $start,
757
                    'enddate' => $end,
758
                    'all_day' => $allDay,
759
                ];
760
761
                if ($updateContent) {
762
                    $attributes['text'] = $content;
763
                }
764
765
                if (!empty($color)) {
766
                    $attributes['color'] = $color;
767
                }
768
769
                Database::update(
770
                    $this->tbl_personal_agenda,
771
                    $attributes,
772
                    ['id = ?' => $id]
773
                );
774
                break;
775
            case 'course':
776
                $eventInfo = $this->get_event($id);
777
778
                if (empty($eventInfo)) {
779
                    return false;
780
                }
781
782
                $groupId = api_get_group_id();
783
                $groupIid = 0;
784
                $groupInfo = [];
785
                if ($groupId) {
786
                    $groupInfo = GroupManager::get_group_properties($groupId);
787
                    if ($groupInfo) {
788
                        $groupIid = $groupInfo['iid'];
789
                    }
790
                }
791
792
                $courseId = $this->course['real_id'];
793
794
                if (empty($courseId)) {
795
                    return false;
796
                }
797
798
                if ($this->getIsAllowedToEdit()) {
799
                    $attributes = [
800
                        'title' => $title,
801
                        'start_date' => $start,
802
                        'end_date' => $end,
803
                        'all_day' => $allDay,
804
                        'comment' => $comment,
805
                    ];
806
807
                    if ($updateContent) {
808
                        $attributes['content'] = $content;
809
                    }
810
811
                    if (!empty($color)) {
812
                        $attributes['color'] = $color;
813
                    }
814
815
                    Database::update(
816
                        $this->tbl_course_agenda,
817
                        $attributes,
818
                        [
819
                            'id = ? AND c_id = ? AND session_id = ? ' => [
820
                                $id,
821
                                $courseId,
822
                                $this->sessionId,
823
                            ],
824
                        ]
825
                    );
826
827
                    if (!empty($usersToSend)) {
828
                        $sendTo = $this->parseSendToArray($usersToSend);
829
830
                        $usersToDelete = array_diff(
831
                            $eventInfo['send_to']['users'],
832
                            $sendTo['users']
833
                        );
834
                        $usersToAdd = array_diff(
835
                            $sendTo['users'],
836
                            $eventInfo['send_to']['users']
837
                        );
838
839
                        $groupsToDelete = array_diff(
840
                            $eventInfo['send_to']['groups'],
841
                            $sendTo['groups']
842
                        );
843
                        $groupToAdd = array_diff(
844
                            $sendTo['groups'],
845
                            $eventInfo['send_to']['groups']
846
                        );
847
848
                        if ($sendTo['everyone']) {
849
                            // Delete all from group
850
                            if (isset($eventInfo['send_to']['groups']) &&
851
                                !empty($eventInfo['send_to']['groups'])
852
                            ) {
853
                                foreach ($eventInfo['send_to']['groups'] as $group) {
854
                                    $groupIidItem = 0;
855
                                    if ($group) {
856
                                        $groupInfoItem = GroupManager::get_group_properties(
857
                                            $group
858
                                        );
859
                                        if ($groupInfoItem) {
860
                                            $groupIidItem = $groupInfoItem['iid'];
861
                                        }
862
                                    }
863
864
                                    api_item_property_delete(
865
                                        $this->course,
866
                                        TOOL_CALENDAR_EVENT,
867
                                        $id,
868
                                        0,
869
                                        $groupIidItem,
870
                                        $this->sessionId
871
                                    );
872
                                }
873
                            }
874
875
                            // Storing the selected users.
876
                            if (isset($eventInfo['send_to']['users']) &&
877
                                !empty($eventInfo['send_to']['users'])
878
                            ) {
879
                                foreach ($eventInfo['send_to']['users'] as $userId) {
880
                                    api_item_property_delete(
881
                                        $this->course,
882
                                        TOOL_CALENDAR_EVENT,
883
                                        $id,
884
                                        $userId,
885
                                        $groupIid,
886
                                        $this->sessionId
887
                                    );
888
                                }
889
                            }
890
891
                            // Add to everyone only.
892
                            api_item_property_update(
893
                                $this->course,
894
                                TOOL_CALENDAR_EVENT,
895
                                $id,
896
                                'visible',
897
                                $authorId,
898
                                $groupInfo,
899
                                null,
900
                                $start,
901
                                $end,
902
                                $this->sessionId
903
                            );
904
                        } else {
905
                            // Delete "everyone".
906
                            api_item_property_delete(
907
                                $this->course,
908
                                TOOL_CALENDAR_EVENT,
909
                                $id,
910
                                0,
911
                                0,
912
                                $this->sessionId
913
                            );
914
915
                            // Add groups
916
                            if (!empty($groupToAdd)) {
917
                                foreach ($groupToAdd as $group) {
918
                                    $groupInfoItem = [];
919
                                    if ($group) {
920
                                        $groupInfoItem = GroupManager::get_group_properties(
921
                                            $group
922
                                        );
923
                                    }
924
925
                                    api_item_property_update(
926
                                        $this->course,
927
                                        TOOL_CALENDAR_EVENT,
928
                                        $id,
929
                                        'visible',
930
                                        $authorId,
931
                                        $groupInfoItem,
932
                                        0,
933
                                        $start,
934
                                        $end,
935
                                        $this->sessionId
936
                                    );
937
                                }
938
                            }
939
940
                            // Delete groups.
941
                            if (!empty($groupsToDelete)) {
942
                                foreach ($groupsToDelete as $group) {
943
                                    $groupIidItem = 0;
944
                                    $groupInfoItem = [];
945
                                    if ($group) {
946
                                        $groupInfoItem = GroupManager::get_group_properties(
947
                                            $group
948
                                        );
949
                                        if ($groupInfoItem) {
950
                                            $groupIidItem = $groupInfoItem['iid'];
951
                                        }
952
                                    }
953
954
                                    api_item_property_delete(
955
                                        $this->course,
956
                                        TOOL_CALENDAR_EVENT,
957
                                        $id,
958
                                        0,
959
                                        $groupIidItem,
960
                                        $this->sessionId
961
                                    );
962
                                }
963
                            }
964
965
                            // Add users.
966
                            if (!empty($usersToAdd)) {
967
                                foreach ($usersToAdd as $userId) {
968
                                    api_item_property_update(
969
                                        $this->course,
970
                                        TOOL_CALENDAR_EVENT,
971
                                        $id,
972
                                        'visible',
973
                                        $authorId,
974
                                        $groupInfo,
975
                                        $userId,
976
                                        $start,
977
                                        $end,
978
                                        $this->sessionId
979
                                    );
980
                                }
981
                            }
982
983
                            // Delete users.
984
                            if (!empty($usersToDelete)) {
985
                                foreach ($usersToDelete as $userId) {
986
                                    api_item_property_delete(
987
                                        $this->course,
988
                                        TOOL_CALENDAR_EVENT,
989
                                        $id,
990
                                        $userId,
991
                                        $groupInfo,
992
                                        $this->sessionId
993
                                    );
994
                                }
995
                            }
996
                        }
997
                    }
998
999
                    // Add announcement.
1000
                    if (isset($addAnnouncement) && !empty($addAnnouncement)) {
1001
                        $this->storeAgendaEventAsAnnouncement(
1002
                            $id,
1003
                            $usersToSend
1004
                        );
1005
                    }
1006
1007
                    // Add attachment.
1008
                    if (isset($attachmentArray) && !empty($attachmentArray)) {
1009
                        $counter = 0;
1010
                        foreach ($attachmentArray as $attachmentItem) {
1011
                            $this->updateAttachment(
1012
                                $attachmentItem['id'],
1013
                                $id,
1014
                                $attachmentItem,
1015
                                $attachmentCommentList[$counter],
1016
                                $this->course
1017
                            );
1018
                            $counter++;
1019
                        }
1020
                    }
1021
1022
                    return true;
1023
                } else {
1024
                    return false;
1025
                }
1026
                break;
1027
            case 'admin':
1028
            case 'platform':
1029
                if (api_is_platform_admin()) {
1030
                    $attributes = [
1031
                        'title' => $title,
1032
                        'start_date' => $start,
1033
                        'end_date' => $end,
1034
                        'all_day' => $allDay,
1035
                    ];
1036
1037
                    if ($updateContent) {
1038
                        $attributes['content'] = $content;
1039
                    }
1040
                    Database::update(
1041
                        $this->tbl_global_agenda,
1042
                        $attributes,
1043
                        ['id = ?' => $id]
1044
                    );
1045
                }
1046
                break;
1047
        }
1048
    }
1049
1050
    /**
1051
     * @param int  $id
1052
     * @param bool $deleteAllItemsFromSerie
1053
     */
1054
    public function deleteEvent($id, $deleteAllItemsFromSerie = false)
1055
    {
1056
        switch ($this->type) {
1057
            case 'personal':
1058
                $eventInfo = $this->get_event($id);
1059
                if ($eventInfo['user'] == api_get_user_id()) {
1060
                    Database::delete(
1061
                        $this->tbl_personal_agenda,
1062
                        ['id = ?' => $id]
1063
                    );
1064
                }
1065
                break;
1066
            case 'course':
1067
                $courseId = api_get_course_int_id();
1068
                $sessionId = api_get_session_id();
1069
                $isAllowToEdit = api_is_allowed_to_edit(null, true);
1070
1071
                if ($isAllowToEdit == false && !empty($sessionId)) {
1072
                    $allowDhrToEdit = api_get_configuration_value('allow_agenda_edit_for_hrm');
1073
                    if ($allowDhrToEdit) {
1074
                        $isHrm = SessionManager::isUserSubscribedAsHRM(
1075
                            $sessionId,
1076
                            api_get_user_id()
1077
                        );
1078
                        if ($isHrm) {
1079
                            $isAllowToEdit = true;
1080
                        }
1081
                    }
1082
                }
1083
1084
                if (!empty($courseId) && $isAllowToEdit) {
1085
                    // Delete
1086
                    $eventInfo = $this->get_event($id);
1087
                    if ($deleteAllItemsFromSerie) {
1088
                        /* This is one of the children.
1089
                           Getting siblings and delete 'Em all + the father! */
1090
                        if (isset($eventInfo['parent_event_id']) && !empty($eventInfo['parent_event_id'])) {
1091
                            // Removing items.
1092
                            $events = $this->getAllRepeatEvents(
1093
                                $eventInfo['parent_event_id']
1094
                            );
1095
                            if (!empty($events)) {
1096
                                foreach ($events as $event) {
1097
                                    $this->deleteEvent($event['id']);
1098
                                }
1099
                            }
1100
                            // Removing parent.
1101
                            $this->deleteEvent($eventInfo['parent_event_id']);
1102
                        } else {
1103
                            // This is the father looking for the children.
1104
                            $events = $this->getAllRepeatEvents($id);
1105
                            if (!empty($events)) {
1106
                                foreach ($events as $event) {
1107
                                    $this->deleteEvent($event['id']);
1108
                                }
1109
                            }
1110
                        }
1111
                    }
1112
1113
                    // Removing from events.
1114
                    Database::delete(
1115
                        $this->tbl_course_agenda,
1116
                        ['id = ? AND c_id = ?' => [$id, $courseId]]
1117
                    );
1118
1119
                    api_item_property_update(
1120
                        $this->course,
1121
                        TOOL_CALENDAR_EVENT,
1122
                        $id,
1123
                        'delete',
1124
                        api_get_user_id()
1125
                    );
1126
1127
                    // Removing from series.
1128
                    Database::delete(
1129
                        $this->table_repeat,
1130
                        [
1131
                            'cal_id = ? AND c_id = ?' => [
1132
                                $id,
1133
                                $courseId,
1134
                            ],
1135
                        ]
1136
                    );
1137
1138
                    if (isset($eventInfo['attachment']) && !empty($eventInfo['attachment'])) {
1139
                        foreach ($eventInfo['attachment'] as $attachment) {
1140
                            self::deleteAttachmentFile(
1141
                                $attachment['id'],
1142
                                $this->course
1143
                            );
1144
                        }
1145
                    }
1146
                }
1147
                break;
1148
            case 'admin':
1149
                if (api_is_platform_admin()) {
1150
                    Database::delete(
1151
                        $this->tbl_global_agenda,
1152
                        ['id = ?' => $id]
1153
                    );
1154
                }
1155
                break;
1156
        }
1157
    }
1158
1159
    /**
1160
     * Get agenda events.
1161
     *
1162
     * @param int    $start
1163
     * @param int    $end
1164
     * @param int    $courseId
1165
     * @param int    $groupId
1166
     * @param int    $user_id
1167
     * @param string $format
1168
     *
1169
     * @return array|string
1170
     */
1171
    public function getEvents(
1172
        $start,
1173
        $end,
1174
        $courseId = null,
1175
        $groupId = null,
1176
        $user_id = 0,
1177
        $format = 'json'
1178
    ) {
1179
        switch ($this->type) {
1180
            case 'admin':
1181
                $this->getPlatformEvents($start, $end);
1182
                break;
1183
            case 'course':
1184
                $courseInfo = api_get_course_info_by_id($courseId);
1185
1186
                // Session coach can see all events inside a session.
1187
                if (api_is_coach()) {
1188
                    // Own course
1189
                    $this->getCourseEvents(
1190
                        $start,
1191
                        $end,
1192
                        $courseInfo,
1193
                        $groupId,
1194
                        $this->sessionId,
1195
                        $user_id
1196
                    );
1197
1198
                    // Others
1199
                    $this->getSessionEvents(
1200
                        $start,
1201
                        $end,
1202
                        $this->sessionId,
1203
                        $user_id,
1204
                        $this->eventOtherSessionColor
1205
                    );
1206
                } else {
1207
                    $this->getCourseEvents(
1208
                        $start,
1209
                        $end,
1210
                        $courseInfo,
1211
                        $groupId,
1212
                        $this->sessionId,
1213
                        $user_id
1214
                    );
1215
                }
1216
                break;
1217
            case 'personal':
1218
            default:
1219
                $sessionFilterActive = false;
1220
                if (!empty($this->sessionId)) {
1221
                    $sessionFilterActive = true;
1222
                }
1223
1224
                if ($sessionFilterActive == false) {
1225
                    // Getting personal events
1226
                    $this->getPersonalEvents($start, $end);
1227
1228
                    // Getting platform/admin events
1229
                    $this->getPlatformEvents($start, $end);
1230
                }
1231
1232
                $ignoreVisibility = api_get_configuration_value('personal_agenda_show_all_session_events');
1233
1234
                // Getting course events
1235
                $my_course_list = [];
1236
                if (!api_is_anonymous()) {
1237
                    $session_list = SessionManager::get_sessions_by_user(
1238
                        api_get_user_id(),
1239
                        $ignoreVisibility
1240
                    );
1241
                    $my_course_list = CourseManager::get_courses_list_by_user_id(
1242
                        api_get_user_id(),
1243
                        false
1244
                    );
1245
                }
1246
1247
                if (api_is_drh()) {
1248
                    if (api_drh_can_access_all_session_content()) {
1249
                        $session_list = [];
1250
                        $sessionList = SessionManager::get_sessions_followed_by_drh(
1251
                            api_get_user_id(),
1252
                            null,
1253
                            null,
1254
                            null,
1255
                            true,
1256
                            false
1257
                        );
1258
1259
                        if (!empty($sessionList)) {
1260
                            foreach ($sessionList as $sessionItem) {
1261
                                $sessionId = $sessionItem['id'];
1262
                                $courses = SessionManager::get_course_list_by_session_id(
1263
                                    $sessionId
1264
                                );
1265
                                $sessionInfo = [
1266
                                    'session_id' => $sessionId,
1267
                                    'courses' => $courses,
1268
                                ];
1269
                                $session_list[] = $sessionInfo;
1270
                            }
1271
                        }
1272
                    }
1273
                }
1274
1275
                if (!empty($session_list)) {
1276
                    foreach ($session_list as $session_item) {
1277
                        if ($sessionFilterActive) {
1278
                            if ($this->sessionId != $session_item['session_id']) {
1279
                                continue;
1280
                            }
1281
                        }
1282
1283
                        $my_courses = $session_item['courses'];
1284
                        $my_session_id = $session_item['session_id'];
1285
1286
                        if (!empty($my_courses)) {
1287
                            foreach ($my_courses as $course_item) {
1288
                                $courseInfo = api_get_course_info_by_id(
1289
                                    $course_item['real_id']
1290
                                );
1291
                                $this->getCourseEvents(
1292
                                    $start,
1293
                                    $end,
1294
                                    $courseInfo,
1295
                                    0,
1296
                                    $my_session_id
1297
                                );
1298
                            }
1299
                        }
1300
                    }
1301
                }
1302
1303
                if (!empty($my_course_list) && $sessionFilterActive == false) {
1304
                    foreach ($my_course_list as $courseInfoItem) {
1305
                        $courseInfo = api_get_course_info_by_id(
1306
                            $courseInfoItem['real_id']
1307
                        );
1308
                        if (isset($courseId) && !empty($courseId)) {
1309
                            if ($courseInfo['real_id'] == $courseId) {
1310
                                $this->getCourseEvents(
1311
                                    $start,
1312
                                    $end,
1313
                                    $courseInfo,
1314
                                    0,
1315
                                    0,
1316
                                    $user_id
1317
                                );
1318
                            }
1319
                        } else {
1320
                            $this->getCourseEvents(
1321
                                $start,
1322
                                $end,
1323
                                $courseInfo,
1324
                                0,
1325
                                0,
1326
                                $user_id
1327
                            );
1328
                        }
1329
                    }
1330
                }
1331
                break;
1332
        }
1333
1334
        $this->cleanEvents();
1335
1336
        switch ($format) {
1337
            case 'json':
1338
                if (empty($this->events)) {
1339
                    return '[]';
1340
                }
1341
1342
                return json_encode($this->events);
1343
                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...
1344
            case 'array':
1345
                if (empty($this->events)) {
1346
                    return [];
1347
                }
1348
1349
                return $this->events;
1350
                break;
1351
        }
1352
    }
1353
1354
    /**
1355
     * Clean events.
1356
     *
1357
     * @return bool
1358
     */
1359
    public function cleanEvents()
1360
    {
1361
        if (empty($this->events)) {
1362
            return false;
1363
        }
1364
1365
        foreach ($this->events as &$event) {
1366
            $event['description'] = Security::remove_XSS($event['description']);
1367
            $event['title'] = Security::remove_XSS($event['title']);
1368
        }
1369
1370
        return true;
1371
    }
1372
1373
    /**
1374
     * @param int $id
1375
     * @param int $minute_delta
1376
     *
1377
     * @return int
1378
     */
1379
    public function resizeEvent($id, $minute_delta)
1380
    {
1381
        $id = (int) $id;
1382
        $delta = (int) $minute_delta;
1383
        $event = $this->get_event($id);
1384
        if (!empty($event)) {
1385
            switch ($this->type) {
1386
                case 'personal':
1387
                    $sql = "UPDATE $this->tbl_personal_agenda SET
1388
                            enddate = DATE_ADD(enddate, INTERVAL $delta MINUTE)
1389
							WHERE id = ".$id;
1390
                    Database::query($sql);
1391
                    break;
1392
                case 'course':
1393
                    $sql = "UPDATE $this->tbl_course_agenda SET
1394
                            end_date = DATE_ADD(end_date, INTERVAL $delta MINUTE)
1395
							WHERE 
1396
							    c_id = ".$this->course['real_id']." AND 
1397
							    id = ".$id;
1398
                    Database::query($sql);
1399
                    break;
1400
                case 'admin':
1401
                    $sql = "UPDATE $this->tbl_global_agenda SET
1402
                            end_date = DATE_ADD(end_date, INTERVAL $delta MINUTE)
1403
							WHERE id = ".$id;
1404
                    Database::query($sql);
1405
                    break;
1406
            }
1407
        }
1408
1409
        return 1;
1410
    }
1411
1412
    /**
1413
     * @param int $id
1414
     * @param int $minute_delta minutes
1415
     * @param int $allDay
1416
     *
1417
     * @return int
1418
     */
1419
    public function move_event($id, $minute_delta, $allDay)
1420
    {
1421
        $id = (int) $id;
1422
        $event = $this->get_event($id);
1423
1424
        if (empty($event)) {
1425
            return false;
1426
        }
1427
1428
        // we convert the hour delta into minutes and add the minute delta
1429
        $delta = (int) $minute_delta;
1430
        $allDay = (int) $allDay;
1431
1432
        if (!empty($event)) {
1433
            switch ($this->type) {
1434
                case 'personal':
1435
                    $sql = "UPDATE $this->tbl_personal_agenda SET
1436
                            all_day = $allDay, date = DATE_ADD(date, INTERVAL $delta MINUTE),
1437
                            enddate = DATE_ADD(enddate, INTERVAL $delta MINUTE)
1438
							WHERE id=".$id;
1439
                    Database::query($sql);
1440
                    break;
1441
                case 'course':
1442
                    $sql = "UPDATE $this->tbl_course_agenda SET
1443
                            all_day = $allDay, 
1444
                            start_date = DATE_ADD(start_date, INTERVAL $delta MINUTE),
1445
                            end_date = DATE_ADD(end_date, INTERVAL $delta MINUTE)
1446
							WHERE 
1447
							    c_id = ".$this->course['real_id']." AND 
1448
							    id=".$id;
1449
                    Database::query($sql);
1450
                    break;
1451
                case 'admin':
1452
                    $sql = "UPDATE $this->tbl_global_agenda SET
1453
                            all_day = $allDay,
1454
                            start_date = DATE_ADD(start_date,INTERVAL $delta MINUTE),
1455
                            end_date = DATE_ADD(end_date, INTERVAL $delta MINUTE)
1456
							WHERE id=".$id;
1457
                    Database::query($sql);
1458
                    break;
1459
            }
1460
        }
1461
1462
        return 1;
1463
    }
1464
1465
    /**
1466
     * Gets a single event.
1467
     *
1468
     * @param int $id event id
1469
     *
1470
     * @return array
1471
     */
1472
    public function get_event($id)
1473
    {
1474
        // make sure events of the personal agenda can only be seen by the user himself
1475
        $id = (int) $id;
1476
        $event = null;
1477
        switch ($this->type) {
1478
            case 'personal':
1479
                $sql = "SELECT * FROM ".$this->tbl_personal_agenda."
1480
                        WHERE id = $id AND user = ".api_get_user_id();
1481
                $result = Database::query($sql);
1482
                if (Database::num_rows($result)) {
1483
                    $event = Database::fetch_array($result, 'ASSOC');
1484
                    $event['description'] = $event['text'];
1485
                    $event['content'] = $event['text'];
1486
                    $event['start_date'] = $event['date'];
1487
                    $event['end_date'] = $event['enddate'];
1488
                }
1489
                break;
1490
            case 'course':
1491
                if (!empty($this->course['real_id'])) {
1492
                    $sql = "SELECT * FROM ".$this->tbl_course_agenda."
1493
                            WHERE c_id = ".$this->course['real_id']." AND id = ".$id;
1494
                    $result = Database::query($sql);
1495
                    if (Database::num_rows($result)) {
1496
                        $event = Database::fetch_array($result, 'ASSOC');
1497
                        $event['description'] = $event['content'];
1498
1499
                        // Getting send to array
1500
                        $event['send_to'] = $this->getUsersAndGroupSubscribedToEvent(
1501
                            $id,
1502
                            $this->course['real_id'],
1503
                            $this->sessionId
1504
                        );
1505
1506
                        // Getting repeat info
1507
                        $event['repeat_info'] = $this->getRepeatedInfoByEvent(
1508
                            $id,
1509
                            $this->course['real_id']
1510
                        );
1511
1512
                        if (!empty($event['parent_event_id'])) {
1513
                            $event['parent_info'] = $this->get_event(
1514
                                $event['parent_event_id']
1515
                            );
1516
                        }
1517
1518
                        $event['attachment'] = $this->getAttachmentList(
1519
                            $id,
1520
                            $this->course
1521
                        );
1522
                    }
1523
                }
1524
                break;
1525
            case 'admin':
1526
            case 'platform':
1527
                $sql = "SELECT * FROM ".$this->tbl_global_agenda."
1528
                        WHERE id = $id";
1529
                $result = Database::query($sql);
1530
                if (Database::num_rows($result)) {
1531
                    $event = Database::fetch_array($result, 'ASSOC');
1532
                    $event['description'] = $event['content'];
1533
                }
1534
                break;
1535
        }
1536
1537
        return $event;
1538
    }
1539
1540
    /**
1541
     * Gets personal events.
1542
     *
1543
     * @param int $start
1544
     * @param int $end
1545
     *
1546
     * @return array
1547
     */
1548
    public function getPersonalEvents($start, $end)
1549
    {
1550
        $start = (int) $start;
1551
        $end = (int) $end;
1552
        $startCondition = '';
1553
        $endCondition = '';
1554
1555
        if ($start !== 0) {
1556
            $startCondition = "AND date >= '".api_get_utc_datetime($start)."'";
1557
        }
1558
        if ($start !== 0) {
1559
            $endCondition = "AND (enddate <= '".api_get_utc_datetime($end)."' OR enddate IS NULL)";
1560
        }
1561
        $user_id = api_get_user_id();
1562
1563
        $sql = "SELECT * FROM ".$this->tbl_personal_agenda."
1564
                WHERE user = $user_id $startCondition $endCondition";
1565
1566
        $result = Database::query($sql);
1567
        $my_events = [];
1568
        if (Database::num_rows($result)) {
1569
            while ($row = Database::fetch_array($result, 'ASSOC')) {
1570
                $event = [];
1571
                $event['id'] = 'personal_'.$row['id'];
1572
                $event['title'] = $row['title'];
1573
                $event['className'] = 'personal';
1574
                $event['borderColor'] = $event['backgroundColor'] = $this->event_personal_color;
1575
                $event['editable'] = true;
1576
                $event['sent_to'] = get_lang('Me');
1577
                $event['type'] = 'personal';
1578
1579
                if (!empty($row['date'])) {
1580
                    $event['start'] = $this->formatEventDate($row['date']);
1581
                    $event['start_date_localtime'] = api_get_local_time($row['date']);
1582
                }
1583
1584
                if (!empty($row['enddate'])) {
1585
                    $event['end'] = $this->formatEventDate($row['enddate']);
1586
                    $event['end_date_localtime'] = api_get_local_time($row['enddate']);
1587
                }
1588
1589
                $event['description'] = $row['text'];
1590
                $event['allDay'] = isset($row['all_day']) && $row['all_day'] == 1 ? $row['all_day'] : 0;
1591
                $event['parent_event_id'] = 0;
1592
                $event['has_children'] = 0;
1593
1594
                $my_events[] = $event;
1595
                $this->events[] = $event;
1596
            }
1597
        }
1598
1599
        // Add plugin personal events
1600
1601
        $this->plugin = new AppPlugin();
1602
        $plugins = $this->plugin->getInstalledPluginListObject();
1603
        /** @var Plugin $plugin */
1604
        foreach ($plugins as $plugin) {
1605
            if ($plugin->hasPersonalEvents && method_exists($plugin, 'getPersonalEvents')) {
1606
                $pluginEvents = $plugin->getPersonalEvents($this, $start, $end);
1607
1608
                if (!empty($pluginEvents)) {
1609
                    $this->events = array_merge($this->events, $pluginEvents);
1610
                }
1611
            }
1612
        }
1613
1614
        return $my_events;
1615
    }
1616
1617
    /**
1618
     * Get user/group list per event.
1619
     *
1620
     * @param int $eventId
1621
     * @param int $courseId
1622
     * @param int $sessionId
1623
     * @paraù int $sessionId
1624
     *
1625
     * @return array
1626
     */
1627
    public function getUsersAndGroupSubscribedToEvent(
1628
        $eventId,
1629
        $courseId,
1630
        $sessionId
1631
    ) {
1632
        $eventId = (int) $eventId;
1633
        $courseId = (int) $courseId;
1634
        $sessionId = (int) $sessionId;
1635
1636
        $sessionCondition = "ip.session_id = $sessionId";
1637
        if (empty($sessionId)) {
1638
            $sessionCondition = " (ip.session_id = 0 OR ip.session_id IS NULL) ";
1639
        }
1640
1641
        $tlb_course_agenda = Database::get_course_table(TABLE_AGENDA);
1642
        $tbl_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1643
1644
        // Get sent_tos
1645
        $sql = "SELECT DISTINCT to_user_id, to_group_id
1646
                FROM $tbl_property ip
1647
                INNER JOIN $tlb_course_agenda agenda
1648
                ON (
1649
                  ip.ref = agenda.id AND
1650
                  ip.c_id = agenda.c_id AND
1651
                  ip.tool = '".TOOL_CALENDAR_EVENT."'
1652
                )
1653
                WHERE
1654
                    ref = $eventId AND
1655
                    ip.visibility = '1' AND
1656
                    ip.c_id = $courseId AND
1657
                    $sessionCondition
1658
                ";
1659
1660
        $result = Database::query($sql);
1661
        $users = [];
1662
        $groups = [];
1663
        $everyone = false;
1664
1665
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1666
            if (!empty($row['to_group_id'])) {
1667
                $groups[] = $row['to_group_id'];
1668
            }
1669
            if (!empty($row['to_user_id'])) {
1670
                $users[] = $row['to_user_id'];
1671
            }
1672
1673
            if (empty($groups) && empty($users)) {
1674
                if ($row['to_group_id'] == 0) {
1675
                    $everyone = true;
1676
                }
1677
            }
1678
        }
1679
1680
        return [
1681
            'everyone' => $everyone,
1682
            'users' => $users,
1683
            'groups' => $groups,
1684
        ];
1685
    }
1686
1687
    /**
1688
     * @param int    $start
1689
     * @param int    $end
1690
     * @param int    $sessionId
1691
     * @param int    $userId
1692
     * @param string $color
1693
     *
1694
     * @return array
1695
     */
1696
    public function getSessionEvents(
1697
        $start,
1698
        $end,
1699
        $sessionId = 0,
1700
        $userId = 0,
1701
        $color = ''
1702
    ) {
1703
        $courses = SessionManager::get_course_list_by_session_id($sessionId);
1704
1705
        if (!empty($courses)) {
1706
            foreach ($courses as $course) {
1707
                $this->getCourseEvents(
1708
                    $start,
1709
                    $end,
1710
                    $course,
1711
                    0,
1712
                    $sessionId,
1713
                    0,
1714
                    $color
1715
                );
1716
            }
1717
        }
1718
    }
1719
1720
    /**
1721
     * @param int    $start
1722
     * @param int    $end
1723
     * @param array  $courseInfo
1724
     * @param int    $groupId
1725
     * @param int    $sessionId
1726
     * @param int    $user_id
1727
     * @param string $color
1728
     *
1729
     * @return array
1730
     */
1731
    public function getCourseEvents(
1732
        $start,
1733
        $end,
1734
        $courseInfo,
1735
        $groupId = 0,
1736
        $sessionId = 0,
1737
        $user_id = 0,
1738
        $color = ''
1739
    ) {
1740
        $start = isset($start) && !empty($start) ? api_get_utc_datetime(intval($start)) : null;
1741
        $end = isset($end) && !empty($end) ? api_get_utc_datetime(intval($end)) : null;
1742
1743
        if (empty($courseInfo)) {
1744
            return [];
1745
        }
1746
        $courseId = $courseInfo['real_id'];
1747
1748
        if (empty($courseId)) {
1749
            return [];
1750
        }
1751
1752
        $sessionId = (int) $sessionId;
1753
        $user_id = (int) $user_id;
1754
1755
        $groupList = GroupManager::get_group_list(
1756
            null,
1757
            $courseInfo,
1758
            null,
1759
            $sessionId
1760
        );
1761
1762
        $groupNameList = [];
1763
        if (!empty($groupList)) {
1764
            foreach ($groupList as $group) {
1765
                $groupNameList[$group['iid']] = $group['name'];
1766
            }
1767
        }
1768
1769
        if (api_is_platform_admin() || api_is_allowed_to_edit()) {
1770
            $isAllowToEdit = true;
1771
        } else {
1772
            $isAllowToEdit = CourseManager::is_course_teacher(
1773
                api_get_user_id(),
1774
                $courseInfo['code']
1775
            );
1776
        }
1777
1778
        $isAllowToEditByHrm = false;
1779
        if (!empty($sessionId)) {
1780
            $allowDhrToEdit = api_get_configuration_value('allow_agenda_edit_for_hrm');
1781
            if ($allowDhrToEdit) {
1782
                $isHrm = SessionManager::isUserSubscribedAsHRM($sessionId, api_get_user_id());
1783
                if ($isHrm) {
1784
                    $isAllowToEdit = $isAllowToEditByHrm = true;
1785
                }
1786
            }
1787
        }
1788
1789
        $groupMemberships = [];
1790
        if (!empty($groupId)) {
1791
            $groupMemberships = [$groupId];
1792
        } else {
1793
            if ($isAllowToEdit) {
1794
                if (!empty($groupList)) {
1795
                    // c_item_property.to_group_id field was migrated to use
1796
                    // c_group_info.iid
1797
                    $groupMemberships = array_column($groupList, 'iid');
1798
                }
1799
            } else {
1800
                // get only related groups from user
1801
                $groupMemberships = GroupManager::get_group_ids(
1802
                    $courseId,
1803
                    api_get_user_id()
1804
                );
1805
            }
1806
        }
1807
1808
        $tlb_course_agenda = Database::get_course_table(TABLE_AGENDA);
1809
        $tbl_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
1810
1811
        if (empty($sessionId)) {
1812
            $sessionCondition = "
1813
            (
1814
                agenda.session_id = 0 AND (ip.session_id IS NULL OR ip.session_id = 0)
1815
            ) ";
1816
        } else {
1817
            $sessionCondition = "
1818
            (
1819
                agenda.session_id = $sessionId AND
1820
                ip.session_id = $sessionId
1821
            ) ";
1822
        }
1823
1824
        if ($isAllowToEdit) {
1825
            // No group filter was asked
1826
            if (empty($groupId)) {
1827
                if (empty($user_id)) {
1828
                    // Show all events not added in group
1829
                    $userCondition = ' (ip.to_group_id IS NULL OR ip.to_group_id = 0) ';
1830
                    // admin see only his stuff
1831
                    if ($this->type === 'personal') {
1832
                        $userCondition = " (ip.to_user_id = ".api_get_user_id()." AND (ip.to_group_id IS NULL OR ip.to_group_id = 0) ) ";
1833
                        $userCondition .= " OR ( (ip.to_user_id = 0 OR ip.to_user_id is NULL)  AND (ip.to_group_id IS NULL OR ip.to_group_id = 0) ) ";
1834
                    }
1835
1836
                    if (!empty($groupMemberships)) {
1837
                        // Show events sent to selected groups
1838
                        $userCondition .= " OR (ip.to_user_id = 0 OR ip.to_user_id is NULL) AND (ip.to_group_id IN (".implode(", ", $groupMemberships).")) ";
1839
                    }
1840
                } else {
1841
                    // Show events of requested user in no group
1842
                    $userCondition = " (ip.to_user_id = $user_id AND (ip.to_group_id IS NULL OR ip.to_group_id = 0)) ";
1843
                    // Show events sent to selected groups
1844
                    if (!empty($groupMemberships)) {
1845
                        $userCondition .= " OR (ip.to_user_id = $user_id) AND (ip.to_group_id IN (".implode(", ", $groupMemberships).")) ";
1846
                    }
1847
                }
1848
            } else {
1849
                // Show only selected groups (depending of user status)
1850
                $userCondition = " (ip.to_user_id = 0 OR ip.to_user_id is NULL) AND (ip.to_group_id IN (".implode(", ", $groupMemberships).")) ";
1851
1852
                if (!empty($groupMemberships)) {
1853
                    // Show send to $user_id in selected groups
1854
                    $userCondition .= " OR (ip.to_user_id = $user_id) AND (ip.to_group_id IN (".implode(", ", $groupMemberships).")) ";
1855
                }
1856
            }
1857
        } else {
1858
            // No group filter was asked
1859
            if (empty($groupId)) {
1860
                // Show events sent to everyone and no group
1861
                $userCondition = ' ( (ip.to_user_id = 0 OR ip.to_user_id is NULL) AND (ip.to_group_id IS NULL OR ip.to_group_id = 0) ';
1862
1863
                // Show events sent to selected groups
1864
                if (!empty($groupMemberships)) {
1865
                    $userCondition .= " OR (ip.to_user_id = 0 OR ip.to_user_id is NULL) AND (ip.to_group_id IN (".implode(", ", $groupMemberships)."))) ";
1866
                } else {
1867
                    $userCondition .= " ) ";
1868
                }
1869
                $userCondition .= " OR (ip.to_user_id = ".api_get_user_id()." AND (ip.to_group_id IS NULL OR ip.to_group_id = 0)) ";
1870
            } else {
1871
                if (!empty($groupMemberships)) {
1872
                    // Show send to everyone - and only selected groups
1873
                    $userCondition = " (ip.to_user_id = 0 OR ip.to_user_id is NULL) AND (ip.to_group_id IN (".implode(", ", $groupMemberships).")) ";
1874
                }
1875
            }
1876
1877
            // Show sent to only me and no group
1878
            if (!empty($groupMemberships)) {
1879
                $userCondition .= " OR (ip.to_user_id = ".api_get_user_id().") AND (ip.to_group_id IN (".implode(", ", $groupMemberships).")) ";
1880
            } else {
1881
                // Show sent to only me and selected groups
1882
            }
1883
        }
1884
1885
        if (api_is_allowed_to_edit()) {
1886
            $visibilityCondition = " (ip.visibility IN ('1', '0'))  ";
1887
        } else {
1888
            $visibilityCondition = " (ip.visibility = '1') ";
1889
        }
1890
1891
        $sql = "SELECT DISTINCT
1892
                    agenda.*,
1893
                    ip.visibility,
1894
                    ip.to_group_id,
1895
                    ip.insert_user_id,
1896
                    ip.ref,
1897
                    to_user_id
1898
                FROM $tlb_course_agenda agenda
1899
                INNER JOIN $tbl_property ip
1900
                ON (
1901
                    agenda.id = ip.ref AND 
1902
                    agenda.c_id = ip.c_id AND 
1903
                    ip.tool = '".TOOL_CALENDAR_EVENT."'
1904
                )
1905
                WHERE
1906
                    $sessionCondition AND
1907
                    ($userCondition) AND
1908
                    $visibilityCondition AND
1909
                    agenda.c_id = $courseId
1910
        ";
1911
        $dateCondition = '';
1912
        if (!empty($start) && !empty($end)) {
1913
            $dateCondition .= "AND (
1914
                 agenda.start_date BETWEEN '".$start."' AND '".$end."' OR
1915
                 agenda.end_date BETWEEN '".$start."' AND '".$end."' OR
1916
                 (
1917
                     agenda.start_date IS NOT NULL AND agenda.end_date IS NOT NULL AND
1918
                     YEAR(agenda.start_date) = YEAR(agenda.end_date) AND
1919
                     MONTH('$start') BETWEEN MONTH(agenda.start_date) AND MONTH(agenda.end_date)
1920
                 )
1921
            )";
1922
        }
1923
1924
        $sql .= $dateCondition;
1925
        $result = Database::query($sql);
1926
1927
        $coachCanEdit = false;
1928
        if (!empty($sessionId)) {
1929
            $coachCanEdit = api_is_coach($sessionId, $courseId) || api_is_platform_admin();
1930
        }
1931
1932
        if (Database::num_rows($result)) {
1933
            $eventsAdded = array_column($this->events, 'unique_id');
1934
            while ($row = Database::fetch_array($result, 'ASSOC')) {
1935
                $event = [];
1936
                $event['id'] = 'course_'.$row['id'];
1937
                $event['unique_id'] = $row['iid'];
1938
                // To avoid doubles
1939
                if (in_array($event['unique_id'], $eventsAdded)) {
1940
                    continue;
1941
                }
1942
1943
                $eventsAdded[] = $event['unique_id'];
1944
                $eventId = $row['ref'];
1945
                $items = $this->getUsersAndGroupSubscribedToEvent(
1946
                    $eventId,
1947
                    $courseId,
1948
                    $this->sessionId
1949
                );
1950
                $group_to_array = $items['groups'];
1951
                $user_to_array = $items['users'];
1952
                $attachmentList = $this->getAttachmentList(
1953
                    $row['id'],
1954
                    $courseInfo
1955
                );
1956
                $event['attachment'] = '';
1957
                if (!empty($attachmentList)) {
1958
                    foreach ($attachmentList as $attachment) {
1959
                        $has_attachment = Display::return_icon(
1960
                            'attachment.gif',
1961
                            get_lang('Attachment')
1962
                        );
1963
                        $user_filename = $attachment['filename'];
1964
                        $url = api_get_path(WEB_CODE_PATH).'calendar/download.php?file='.$attachment['path'].'&course_id='.$courseId.'&'.api_get_cidreq();
1965
                        $event['attachment'] .= $has_attachment.
1966
                            Display::url(
1967
                                $user_filename,
1968
                                $url
1969
                            ).'<br />';
1970
                    }
1971
                }
1972
1973
                $event['title'] = $row['title'];
1974
                $event['className'] = 'course';
1975
                $event['allDay'] = 'false';
1976
                $event['course_id'] = $courseId;
1977
                $event['borderColor'] = $event['backgroundColor'] = $this->event_course_color;
1978
1979
                $sessionInfo = [];
1980
                if (isset($row['session_id']) && !empty($row['session_id'])) {
1981
                    $sessionInfo = api_get_session_info($sessionId);
1982
                    $event['borderColor'] = $event['backgroundColor'] = $this->event_session_color;
1983
                }
1984
1985
                $event['session_name'] = isset($sessionInfo['name']) ? $sessionInfo['name'] : '';
1986
                $event['course_name'] = isset($courseInfo['title']) ? $courseInfo['title'] : '';
1987
1988
                if (isset($row['to_group_id']) && !empty($row['to_group_id'])) {
1989
                    $event['borderColor'] = $event['backgroundColor'] = $this->event_group_color;
1990
                }
1991
1992
                if (!empty($color)) {
1993
                    $event['borderColor'] = $event['backgroundColor'] = $color;
1994
                }
1995
1996
                if (isset($row['color']) && !empty($row['color'])) {
1997
                    $event['borderColor'] = $event['backgroundColor'] = $row['color'];
1998
                }
1999
2000
                $event['editable'] = false;
2001
                if ($this->getIsAllowedToEdit() && $this->type == 'course') {
2002
                    $event['editable'] = true;
2003
                    if (!empty($sessionId)) {
2004
                        if ($coachCanEdit == false) {
2005
                            $event['editable'] = false;
2006
                        }
2007
                        if ($isAllowToEditByHrm) {
2008
                            $event['editable'] = true;
2009
                        }
2010
                    }
2011
                    // if user is author then he can edit the item
2012
                    if (api_get_user_id() == $row['insert_user_id']) {
2013
                        $event['editable'] = true;
2014
                    }
2015
                }
2016
2017
                if (!empty($row['start_date'])) {
2018
                    $event['start'] = $this->formatEventDate($row['start_date']);
2019
                    $event['start_date_localtime'] = api_get_local_time($row['start_date']);
2020
                }
2021
                if (!empty($row['end_date'])) {
2022
                    $event['end'] = $this->formatEventDate($row['end_date']);
2023
                    $event['end_date_localtime'] = api_get_local_time($row['end_date']);
2024
                }
2025
2026
                $event['sent_to'] = '';
2027
                $event['type'] = 'course';
2028
                if ($row['session_id'] != 0) {
2029
                    $event['type'] = 'session';
2030
                }
2031
2032
                // Event Sent to a group?
2033
                if (isset($row['to_group_id']) && !empty($row['to_group_id'])) {
2034
                    $sent_to = [];
2035
                    if (!empty($group_to_array)) {
2036
                        foreach ($group_to_array as $group_item) {
2037
                            $sent_to[] = $groupNameList[$group_item];
2038
                        }
2039
                    }
2040
                    $sent_to = implode('@@', $sent_to);
2041
                    $sent_to = str_replace(
2042
                        '@@',
2043
                        '</div><div class="label_tag notice">',
2044
                        $sent_to
2045
                    );
2046
                    $event['sent_to'] = '<div class="label_tag notice">'.$sent_to.'</div>';
2047
                    $event['type'] = 'group';
2048
                }
2049
2050
                // Event sent to a user?
2051
                if (isset($row['to_user_id'])) {
2052
                    $sent_to = [];
2053
                    if (!empty($user_to_array)) {
2054
                        foreach ($user_to_array as $item) {
2055
                            $user_info = api_get_user_info($item);
2056
                            // Add username as tooltip for $event['sent_to'] - ref #4226
2057
                            $username = api_htmlentities(
2058
                                sprintf(
2059
                                    get_lang('LoginX'),
2060
                                    $user_info['username']
2061
                                ),
2062
                                ENT_QUOTES
2063
                            );
2064
                            $sent_to[] = "<span title='".$username."'>".$user_info['complete_name']."</span>";
2065
                        }
2066
                    }
2067
                    $sent_to = implode('@@', $sent_to);
2068
                    $sent_to = str_replace(
2069
                        '@@',
2070
                        '</div><div class="label_tag notice">',
2071
                        $sent_to
2072
                    );
2073
                    $event['sent_to'] = '<div class="label_tag notice">'.$sent_to.'</div>';
2074
                }
2075
2076
                //Event sent to everyone!
2077
                if (empty($event['sent_to'])) {
2078
                    $event['sent_to'] = '<div class="label_tag notice">'.get_lang('Everyone').'</div>';
2079
                }
2080
2081
                $event['description'] = $row['content'];
2082
                $event['visibility'] = $row['visibility'];
2083
                $event['real_id'] = $row['id'];
2084
                $event['allDay'] = isset($row['all_day']) && $row['all_day'] == 1 ? $row['all_day'] : 0;
2085
                $event['parent_event_id'] = $row['parent_event_id'];
2086
                $event['has_children'] = $this->hasChildren($row['id'], $courseId) ? 1 : 0;
2087
                $event['comment'] = $row['comment'];
2088
                $this->events[] = $event;
2089
            }
2090
        }
2091
2092
        return $this->events;
2093
    }
2094
2095
    /**
2096
     * @param int $start tms
2097
     * @param int $end   tms
2098
     *
2099
     * @return array
2100
     */
2101
    public function getPlatformEvents($start, $end)
2102
    {
2103
        $start = isset($start) && !empty($start) ? api_get_utc_datetime(intval($start)) : null;
2104
        $end = isset($end) && !empty($end) ? api_get_utc_datetime(intval($end)) : null;
2105
        $dateCondition = '';
2106
2107
        if (!empty($start) && !empty($end)) {
2108
            $dateCondition .= "AND (
2109
                 start_date BETWEEN '".$start."' AND '".$end."' OR
2110
                 end_date BETWEEN '".$start."' AND '".$end."' OR
2111
                 (
2112
                     start_date IS NOT NULL AND end_date IS NOT NULL AND
2113
                     YEAR(start_date) = YEAR(end_date) AND
2114
                     MONTH('$start') BETWEEN MONTH(start_date) AND MONTH(end_date)
2115
                 )
2116
            )";
2117
        }
2118
2119
        $access_url_id = api_get_current_access_url_id();
2120
2121
        $sql = "SELECT *
2122
                FROM ".$this->tbl_global_agenda."
2123
                WHERE access_url_id = $access_url_id
2124
                $dateCondition";
2125
        $result = Database::query($sql);
2126
        $my_events = [];
2127
        if (Database::num_rows($result)) {
2128
            while ($row = Database::fetch_array($result, 'ASSOC')) {
2129
                $event = [];
2130
                $event['id'] = 'platform_'.$row['id'];
2131
                $event['title'] = $row['title'];
2132
                $event['className'] = 'platform';
2133
                $event['allDay'] = 'false';
2134
                $event['borderColor'] = $event['backgroundColor'] = $this->event_platform_color;
2135
                $event['editable'] = false;
2136
                $event['type'] = 'admin';
2137
2138
                if (api_is_platform_admin() && $this->type === 'admin') {
2139
                    $event['editable'] = true;
2140
                }
2141
2142
                if (!empty($row['start_date'])) {
2143
                    $event['start'] = $this->formatEventDate($row['start_date']);
2144
                    $event['start_date_localtime'] = api_get_local_time($row['start_date']);
2145
                }
2146
2147
                if (!empty($row['end_date'])) {
2148
                    $event['end'] = $this->formatEventDate($row['end_date']);
2149
                    $event['end_date_localtime'] = api_get_local_time($row['end_date']);
2150
                }
2151
                $event['allDay'] = isset($row['all_day']) && $row['all_day'] == 1 ? $row['all_day'] : 0;
2152
                $event['parent_event_id'] = 0;
2153
                $event['has_children'] = 0;
2154
                $event['description'] = $row['content'];
2155
2156
                $my_events[] = $event;
2157
                $this->events[] = $event;
2158
            }
2159
        }
2160
2161
        return $my_events;
2162
    }
2163
2164
    /**
2165
     * @param FormValidator $form
2166
     * @param array         $groupList
2167
     * @param array         $userList
2168
     * @param array         $sendTo               array('users' => [1, 2], 'groups' => [3, 4])
2169
     * @param array         $attributes
2170
     * @param bool          $addOnlyItemsInSendTo
2171
     * @param bool          $required
2172
     */
2173
    public function setSendToSelect(
2174
        $form,
2175
        $groupList = [],
2176
        $userList = [],
2177
        $sendTo = [],
2178
        $attributes = [],
2179
        $addOnlyItemsInSendTo = false,
2180
        $required = false
2181
    ) {
2182
        $params = [
2183
            'id' => 'users_to_send_id',
2184
            'data-placeholder' => get_lang('Select'),
2185
            'multiple' => 'multiple',
2186
            'class' => 'multiple-select',
2187
        ];
2188
2189
        if (!empty($attributes)) {
2190
            $params = array_merge($params, $attributes);
2191
            if (empty($params['multiple'])) {
2192
                unset($params['multiple']);
2193
            }
2194
        }
2195
2196
        $sendToGroups = isset($sendTo['groups']) ? $sendTo['groups'] : [];
2197
        $sendToUsers = isset($sendTo['users']) ? $sendTo['users'] : [];
2198
2199
        /** @var HTML_QuickForm_select $select */
2200
        $select = $form->addSelect(
2201
            'users_to_send',
2202
            get_lang('To'),
2203
            null,
2204
            $params
2205
        );
2206
2207
        if ($required) {
2208
            $form->setRequired($select);
2209
        }
2210
2211
        $selectedEveryoneOptions = [];
2212
        if (isset($sendTo['everyone']) && $sendTo['everyone']) {
2213
            $selectedEveryoneOptions = ['selected'];
2214
            $sendToUsers = [];
2215
        }
2216
2217
        $select->addOption(
2218
            get_lang('Everyone'),
2219
            'everyone',
2220
            $selectedEveryoneOptions
2221
        );
2222
2223
        $options = [];
2224
        if (is_array($groupList)) {
2225
            foreach ($groupList as $group) {
2226
                $count_users = isset($group['count_users']) ? $group['count_users'] : $group['userNb'];
2227
                $count_users = " &ndash; $count_users ".get_lang('Users');
2228
                $option = [
2229
                    'text' => $group['name'].$count_users,
2230
                    'value' => "GROUP:".$group['id'],
2231
                ];
2232
                $selected = in_array(
2233
                    $group['id'],
2234
                    $sendToGroups
2235
                ) ? true : false;
2236
                if ($selected) {
2237
                    $option['selected'] = 'selected';
2238
                }
2239
2240
                if ($addOnlyItemsInSendTo) {
2241
                    if ($selected) {
2242
                        $options[] = $option;
2243
                    }
2244
                } else {
2245
                    $options[] = $option;
2246
                }
2247
            }
2248
            $select->addOptGroup($options, get_lang('Groups'));
2249
        }
2250
2251
        // adding the individual users to the select form
2252
        if (is_array($userList)) {
2253
            $options = [];
2254
            foreach ($userList as $user) {
2255
                if ($user['status'] == ANONYMOUS) {
2256
                    continue;
2257
                }
2258
                $option = [
2259
                    'text' => api_get_person_name(
2260
                            $user['firstname'],
2261
                            $user['lastname']
2262
                        ).' ('.$user['username'].')',
2263
                    'value' => "USER:".$user['user_id'],
2264
                ];
2265
2266
                $selected = in_array(
2267
                    $user['user_id'],
2268
                    $sendToUsers
2269
                ) ? true : false;
2270
2271
                if ($selected) {
2272
                    $option['selected'] = 'selected';
2273
                }
2274
2275
                if ($addOnlyItemsInSendTo) {
2276
                    if ($selected) {
2277
                        $options[] = $option;
2278
                    }
2279
                } else {
2280
                    $options[] = $option;
2281
                }
2282
            }
2283
2284
            $select->addOptGroup($options, get_lang('Users'));
2285
        }
2286
    }
2287
2288
    /**
2289
     * Separates the users and groups array
2290
     * users have a value USER:XXX (with XXX the user id
2291
     * groups have a value GROUP:YYY (with YYY the group id)
2292
     * use the 'everyone' key.
2293
     *
2294
     * @author Julio Montoya based in separate_users_groups in agenda.inc.php
2295
     *
2296
     * @param array $to
2297
     *
2298
     * @return array
2299
     */
2300
    public function parseSendToArray($to)
2301
    {
2302
        $groupList = [];
2303
        $userList = [];
2304
        $sendTo = null;
2305
2306
        $sendTo['everyone'] = false;
2307
        if (is_array($to) && count($to) > 0) {
2308
            foreach ($to as $item) {
2309
                if ($item == 'everyone') {
2310
                    $sendTo['everyone'] = true;
2311
                } else {
2312
                    list($type, $id) = explode(':', $item);
2313
                    switch ($type) {
2314
                        case 'GROUP':
2315
                            $groupList[] = $id;
2316
                            break;
2317
                        case 'USER':
2318
                            $userList[] = $id;
2319
                            break;
2320
                    }
2321
                }
2322
            }
2323
            $sendTo['groups'] = $groupList;
2324
            $sendTo['users'] = $userList;
2325
        }
2326
2327
        return $sendTo;
2328
    }
2329
2330
    /**
2331
     * @param array $params
2332
     *
2333
     * @return FormValidator
2334
     */
2335
    public function getForm($params = [])
2336
    {
2337
        $action = isset($params['action']) ? Security::remove_XSS($params['action']) : null;
2338
        $id = isset($params['id']) ? (int) $params['id'] : 0;
2339
2340
        if ($this->type == 'course') {
2341
            $url = api_get_self().'?'.api_get_cidreq().'&action='.$action.'&id='.$id.'&type='.$this->type;
2342
        } else {
2343
            $url = api_get_self().'?action='.$action.'&id='.$id.'&type='.$this->type;
2344
        }
2345
2346
        $form = new FormValidator(
2347
            'add_event',
2348
            'post',
2349
            $url,
2350
            null,
2351
            ['enctype' => 'multipart/form-data']
2352
        );
2353
2354
        $idAttach = isset($params['id_attach']) ? (int) $params['id_attach'] : null;
2355
        $groupId = api_get_group_id();
2356
        $form_Title = get_lang('AddCalendarItem');
2357
        if (!empty($id)) {
2358
            $form_Title = get_lang('ModifyCalendarItem');
2359
        }
2360
2361
        $form->addHeader($form_Title);
2362
        $form->addElement('hidden', 'id', $id);
2363
        $form->addElement('hidden', 'action', $action);
2364
        $form->addElement('hidden', 'id_attach', $idAttach);
2365
2366
        $isSubEventEdition = false;
2367
        $isParentFromSerie = false;
2368
        $showAttachmentForm = true;
2369
2370
        if ($this->type == 'course') {
2371
            // Edition mode.
2372
            if (!empty($id)) {
2373
                $showAttachmentForm = false;
2374
                if (isset($params['parent_event_id']) && !empty($params['parent_event_id'])) {
2375
                    $isSubEventEdition = true;
2376
                }
2377
                if (!empty($params['repeat_info'])) {
2378
                    $isParentFromSerie = true;
2379
                }
2380
            }
2381
        }
2382
2383
        if ($isSubEventEdition) {
2384
            $form->addElement(
2385
                'label',
2386
                null,
2387
                Display::return_message(
2388
                    get_lang('EditingThisEventWillRemoveItFromTheSerie'),
2389
                    'warning'
2390
                )
2391
            );
2392
        }
2393
2394
        $form->addElement('text', 'title', get_lang('ItemTitle'));
2395
2396
        if (isset($groupId) && !empty($groupId)) {
2397
            $form->addElement(
2398
                'hidden',
2399
                'users_to_send[]',
2400
                "GROUP:$groupId"
2401
            );
2402
            $form->addElement('hidden', 'to', 'true');
2403
        } else {
2404
            $sendTo = isset($params['send_to']) ? $params['send_to'] : ['everyone' => true];
2405
            if ($this->type == 'course') {
2406
                $this->showToForm($form, $sendTo, [], false, true);
2407
            }
2408
        }
2409
2410
        $form->addDateRangePicker(
2411
            'date_range',
2412
            get_lang('DateRange'),
2413
            false,
2414
            ['id' => 'date_range']
2415
        );
2416
        $form->addElement('checkbox', 'all_day', null, get_lang('AllDay'));
2417
2418
        if ($this->type == 'course') {
2419
            $repeat = $form->addElement(
2420
                'checkbox',
2421
                'repeat',
2422
                null,
2423
                get_lang('RepeatEvent'),
2424
                ['onclick' => 'return plus_repeated_event();']
2425
            );
2426
            $form->addElement(
2427
                'html',
2428
                '<div id="options2" style="display:none">'
2429
            );
2430
            $form->addElement(
2431
                'select',
2432
                'repeat_type',
2433
                get_lang('RepeatType'),
2434
                self::getRepeatTypes()
2435
            );
2436
            $form->addElement(
2437
                'date_picker',
2438
                'repeat_end_day',
2439
                get_lang('RepeatEnd'),
2440
                ['id' => 'repeat_end_date_form']
2441
            );
2442
2443
            if ($isSubEventEdition || $isParentFromSerie) {
2444
                $repeatInfo = $params['repeat_info'];
2445
                if ($isSubEventEdition) {
2446
                    $parentEvent = $params['parent_info'];
2447
                    $repeatInfo = $parentEvent['repeat_info'];
2448
                }
2449
                $params['repeat'] = 1;
2450
                $params['repeat_type'] = $repeatInfo['cal_type'];
2451
                $params['repeat_end_day'] = substr(
2452
                    api_get_local_time($repeatInfo['cal_end']),
2453
                    0,
2454
                    10
2455
                );
2456
2457
                $form->freeze(['repeat_type', 'repeat_end_day']);
2458
                $repeat->_attributes['disabled'] = 'disabled';
2459
            }
2460
            $form->addElement('html', '</div>');
2461
        }
2462
2463
        if (!empty($id)) {
2464
            if (empty($params['end_date'])) {
2465
                $params['date_range'] = $params['end_date'];
2466
            }
2467
2468
            $params['date_range'] =
2469
                substr(api_get_local_time($params['start_date']), 0, 16).' / '.
2470
                substr(api_get_local_time($params['end_date']), 0, 16);
2471
        }
2472
2473
        $toolbar = 'Agenda';
2474
        if (!api_is_allowed_to_edit(null, true)) {
2475
            $toolbar = 'AgendaStudent';
2476
        }
2477
2478
        $form->addElement(
2479
            'html_editor',
2480
            'content',
2481
            get_lang('Description'),
2482
            null,
2483
            [
2484
                'ToolbarSet' => $toolbar,
2485
                'Width' => '100%',
2486
                'Height' => '200',
2487
            ]
2488
        );
2489
2490
        if ($this->type == 'course') {
2491
            $form->addElement('textarea', 'comment', get_lang('Comment'));
2492
            $form->addLabel(
2493
                get_lang('FilesAttachment'),
2494
                '<span id="filepaths">
2495
                        <div id="filepath_1">
2496
                            <input type="file" name="attach_1"/><br />
2497
                            '.get_lang('Description').'&nbsp;&nbsp;<input type="text" name="legend[]" /><br /><br />
2498
                        </div>
2499
                    </span>'
2500
            );
2501
2502
            $form->addLabel(
2503
                '',
2504
                '<span id="link-more-attach">
2505
                    <a href="javascript://" onclick="return add_image_form()">'.
2506
                get_lang('AddOneMoreFile').'</a>
2507
                 </span>&nbsp;('.sprintf(
2508
                    get_lang('MaximunFileSizeX'),
2509
                    format_file_size(
2510
                        api_get_setting('message_max_upload_filesize')
2511
                    )
2512
                ).')'
2513
            );
2514
2515
            if (isset($params['attachment']) && !empty($params['attachment'])) {
2516
                $attachmentList = $params['attachment'];
2517
                foreach ($attachmentList as $attachment) {
2518
                    $params['file_comment'] = $attachment['comment'];
2519
                    if (!empty($attachment['path'])) {
2520
                        $form->addElement(
2521
                            'checkbox',
2522
                            'delete_attachment['.$attachment['id'].']',
2523
                            null,
2524
                            get_lang(
2525
                                'DeleteAttachment'
2526
                            ).': '.$attachment['filename']
2527
                        );
2528
                    }
2529
                }
2530
            }
2531
2532
            $form->addElement(
2533
                'textarea',
2534
                'file_comment',
2535
                get_lang('FileComment')
2536
            );
2537
        }
2538
2539
        if (empty($id)) {
2540
            $form->addElement(
2541
                'checkbox',
2542
                'add_announcement',
2543
                null,
2544
                get_lang('AddAnnouncement').'&nbsp('.get_lang('SendMail').')'
2545
            );
2546
        }
2547
2548
        if ($id) {
2549
            $form->addButtonUpdate(get_lang('ModifyEvent'));
2550
        } else {
2551
            $form->addButtonSave(get_lang('AgendaAdd'));
2552
        }
2553
2554
        $form->setDefaults($params);
2555
        $form->addRule(
2556
            'date_range',
2557
            get_lang('ThisFieldIsRequired'),
2558
            'required'
2559
        );
2560
        $form->addRule('title', get_lang('ThisFieldIsRequired'), 'required');
2561
2562
        return $form;
2563
    }
2564
2565
    /**
2566
     * @param FormValidator $form
2567
     * @param array         $sendTo               array('everyone' => false, 'users' => [1, 2], 'groups' => [3, 4])
2568
     * @param array         $attributes
2569
     * @param bool          $addOnlyItemsInSendTo
2570
     * @param bool          $required
2571
     *
2572
     * @return bool
2573
     */
2574
    public function showToForm(
2575
        $form,
2576
        $sendTo = [],
2577
        $attributes = [],
2578
        $addOnlyItemsInSendTo = false,
2579
        $required = false
2580
    ) {
2581
        if ($this->type != 'course') {
2582
            return false;
2583
        }
2584
2585
        $order = 'lastname';
2586
        if (api_is_western_name_order()) {
2587
            $order = 'firstname';
2588
        }
2589
2590
        $userList = CourseManager::get_user_list_from_course_code(
2591
            api_get_course_id(),
2592
            $this->sessionId,
2593
            null,
2594
            $order
2595
        );
2596
2597
        $groupList = CourseManager::get_group_list_of_course(
2598
            api_get_course_id(),
2599
            $this->sessionId
2600
        );
2601
2602
        $this->setSendToSelect(
2603
            $form,
2604
            $groupList,
2605
            $userList,
2606
            $sendTo,
2607
            $attributes,
2608
            $addOnlyItemsInSendTo,
2609
            $required
2610
        );
2611
2612
        return true;
2613
    }
2614
2615
    /**
2616
     * @param int   $id
2617
     * @param int   $visibility 0= invisible, 1 visible
2618
     * @param array $courseInfo
2619
     * @param int   $userId
2620
     */
2621
    public static function changeVisibility(
2622
        $id,
2623
        $visibility,
2624
        $courseInfo,
2625
        $userId = null
2626
    ) {
2627
        $id = intval($id);
2628
        if (empty($userId)) {
2629
            $userId = api_get_user_id();
2630
        } else {
2631
            $userId = intval($userId);
2632
        }
2633
2634
        if ($visibility == 0) {
2635
            api_item_property_update(
2636
                $courseInfo,
2637
                TOOL_CALENDAR_EVENT,
2638
                $id,
2639
                'invisible',
2640
                $userId
2641
            );
2642
        } else {
2643
            api_item_property_update(
2644
                $courseInfo,
2645
                TOOL_CALENDAR_EVENT,
2646
                $id,
2647
                'visible',
2648
                $userId
2649
            );
2650
        }
2651
    }
2652
2653
    /**
2654
     * Get repeat types.
2655
     *
2656
     * @return array
2657
     */
2658
    public static function getRepeatTypes()
2659
    {
2660
        return [
2661
            'daily' => get_lang('RepeatDaily'),
2662
            'weekly' => get_lang('RepeatWeekly'),
2663
            'monthlyByDate' => get_lang('RepeatMonthlyByDate'),
2664
            //monthlyByDay"> get_lang('RepeatMonthlyByDay');
2665
            //monthlyByDayR' => get_lang('RepeatMonthlyByDayR'),
2666
            'yearly' => get_lang('RepeatYearly'),
2667
        ];
2668
    }
2669
2670
    /**
2671
     * Show a list with all the attachments according to the post's id.
2672
     *
2673
     * @param int   $eventId
2674
     * @param array $courseInfo
2675
     *
2676
     * @return array with the post info
2677
     */
2678
    public function getAttachmentList($eventId, $courseInfo)
2679
    {
2680
        $tableAttachment = Database::get_course_table(TABLE_AGENDA_ATTACHMENT);
2681
        $courseId = (int) $courseInfo['real_id'];
2682
        $eventId = (int) $eventId;
2683
2684
        $sql = "SELECT id, path, filename, comment
2685
                FROM $tableAttachment
2686
                WHERE
2687
                    c_id = $courseId AND
2688
                    agenda_id = $eventId";
2689
        $result = Database::query($sql);
2690
        $list = [];
2691
        if (Database::num_rows($result) != 0) {
2692
            $list = Database::store_result($result, 'ASSOC');
2693
        }
2694
2695
        return $list;
2696
    }
2697
2698
    /**
2699
     * Show a list with all the attachments according to the post's id.
2700
     *
2701
     * @param int   $attachmentId
2702
     * @param int   $eventId
2703
     * @param array $courseInfo
2704
     *
2705
     * @return array with the post info
2706
     */
2707
    public function getAttachment($attachmentId, $eventId, $courseInfo)
2708
    {
2709
        $tableAttachment = Database::get_course_table(TABLE_AGENDA_ATTACHMENT);
2710
        $courseId = intval($courseInfo['real_id']);
2711
        $eventId = intval($eventId);
2712
        $attachmentId = intval($attachmentId);
2713
2714
        $row = [];
2715
        $sql = "SELECT id, path, filename, comment
2716
                FROM $tableAttachment
2717
                WHERE
2718
                    c_id = $courseId AND
2719
                    agenda_id = $eventId AND
2720
                    id = $attachmentId
2721
                ";
2722
        $result = Database::query($sql);
2723
        if (Database::num_rows($result) != 0) {
2724
            $row = Database::fetch_array($result, 'ASSOC');
2725
        }
2726
2727
        return $row;
2728
    }
2729
2730
    /**
2731
     * Add an attachment file into agenda.
2732
     *
2733
     * @param int    $eventId
2734
     * @param array  $fileUserUpload ($_FILES['user_upload'])
2735
     * @param string $comment        about file
2736
     * @param array  $courseInfo
2737
     *
2738
     * @return string
2739
     */
2740
    public function addAttachment(
2741
        $eventId,
2742
        $fileUserUpload,
2743
        $comment,
2744
        $courseInfo
2745
    ) {
2746
        $agenda_table_attachment = Database::get_course_table(TABLE_AGENDA_ATTACHMENT);
2747
        $eventId = intval($eventId);
2748
2749
        // Storing the attachments
2750
        $upload_ok = false;
2751
        if (!empty($fileUserUpload['name'])) {
2752
            $upload_ok = process_uploaded_file($fileUserUpload);
2753
        }
2754
2755
        if (!empty($upload_ok)) {
2756
            $courseDir = $courseInfo['directory'].'/upload/calendar';
2757
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
2758
            $uploadDir = $sys_course_path.$courseDir;
2759
2760
            // Try to add an extension to the file if it hasn't one
2761
            $new_file_name = add_ext_on_mime(
2762
                stripslashes($fileUserUpload['name']),
2763
                $fileUserUpload['type']
2764
            );
2765
2766
            // user's file name
2767
            $file_name = $fileUserUpload['name'];
2768
2769
            if (!filter_extension($new_file_name)) {
2770
                return Display::return_message(
2771
                    get_lang('UplUnableToSaveFileFilteredExtension'),
2772
                    'error'
2773
                );
2774
            } else {
2775
                $new_file_name = uniqid('');
2776
                $new_path = $uploadDir.'/'.$new_file_name;
2777
                $result = @move_uploaded_file(
2778
                    $fileUserUpload['tmp_name'],
2779
                    $new_path
2780
                );
2781
                $courseId = api_get_course_int_id();
2782
                $size = intval($fileUserUpload['size']);
2783
                // Storing the attachments if any
2784
                if ($result) {
2785
                    $params = [
2786
                        'c_id' => $courseId,
2787
                        'filename' => $file_name,
2788
                        'comment' => $comment,
2789
                        'path' => $new_file_name,
2790
                        'agenda_id' => $eventId,
2791
                        'size' => $size,
2792
                    ];
2793
                    $id = Database::insert($agenda_table_attachment, $params);
2794
                    if ($id) {
2795
                        $sql = "UPDATE $agenda_table_attachment
2796
                                SET id = iid WHERE iid = $id";
2797
                        Database::query($sql);
2798
2799
                        api_item_property_update(
2800
                            $courseInfo,
2801
                            'calendar_event_attachment',
2802
                            $id,
2803
                            'AgendaAttachmentAdded',
2804
                            api_get_user_id()
2805
                        );
2806
                    }
2807
                }
2808
            }
2809
        }
2810
    }
2811
2812
    /**
2813
     * @param int    $attachmentId
2814
     * @param int    $eventId
2815
     * @param array  $fileUserUpload
2816
     * @param string $comment
2817
     * @param array  $courseInfo
2818
     */
2819
    public function updateAttachment(
2820
        $attachmentId,
2821
        $eventId,
2822
        $fileUserUpload,
2823
        $comment,
2824
        $courseInfo
2825
    ) {
2826
        $attachment = $this->getAttachment(
2827
            $attachmentId,
2828
            $eventId,
2829
            $courseInfo
2830
        );
2831
        if (!empty($attachment)) {
2832
            $this->deleteAttachmentFile($attachmentId, $courseInfo);
2833
        }
2834
        $this->addAttachment($eventId, $fileUserUpload, $comment, $courseInfo);
2835
    }
2836
2837
    /**
2838
     * This function delete a attachment file by id.
2839
     *
2840
     * @param int   $attachmentId
2841
     * @param array $courseInfo
2842
     *
2843
     * @return string
2844
     */
2845
    public function deleteAttachmentFile($attachmentId, $courseInfo)
2846
    {
2847
        $table = Database::get_course_table(TABLE_AGENDA_ATTACHMENT);
2848
        $attachmentId = (int) $attachmentId;
2849
        $courseId = $courseInfo['real_id'];
2850
2851
        if (empty($courseId) || empty($attachmentId)) {
2852
            return false;
2853
        }
2854
2855
        $sql = "DELETE FROM $table
2856
                WHERE c_id = $courseId AND id = ".$attachmentId;
2857
        $result = Database::query($sql);
2858
2859
        // update item_property
2860
        api_item_property_update(
2861
            $courseInfo,
2862
            'calendar_event_attachment',
2863
            $attachmentId,
2864
            'AgendaAttachmentDeleted',
2865
            api_get_user_id()
2866
        );
2867
2868
        if (!empty($result)) {
2869
            return Display::return_message(
2870
                get_lang("AttachmentFileDeleteSuccess"),
2871
                'confirmation'
2872
            );
2873
        }
2874
    }
2875
2876
    /**
2877
     * @param int $eventId
2878
     *
2879
     * @return array
2880
     */
2881
    public function getAllRepeatEvents($eventId)
2882
    {
2883
        $events = [];
2884
        switch ($this->type) {
2885
            case 'personal':
2886
                break;
2887
            case 'course':
2888
                if (!empty($this->course['real_id'])) {
2889
                    $sql = "SELECT * FROM ".$this->tbl_course_agenda."
2890
                            WHERE
2891
                                c_id = ".$this->course['real_id']." AND
2892
                                parent_event_id = ".$eventId;
2893
                    $result = Database::query($sql);
2894
                    if (Database::num_rows($result)) {
2895
                        while ($row = Database::fetch_array($result, 'ASSOC')) {
2896
                            $events[] = $row;
2897
                        }
2898
                    }
2899
                }
2900
                break;
2901
        }
2902
2903
        return $events;
2904
    }
2905
2906
    /**
2907
     * @param int $eventId
2908
     * @param int $courseId
2909
     *
2910
     * @return bool
2911
     */
2912
    public function hasChildren($eventId, $courseId)
2913
    {
2914
        $eventId = (int) $eventId;
2915
        $courseId = (int) $courseId;
2916
2917
        $sql = "SELECT count(DISTINCT(id)) as count
2918
                FROM ".$this->tbl_course_agenda."
2919
                WHERE
2920
                    c_id = $courseId AND
2921
                    parent_event_id = $eventId";
2922
        $result = Database::query($sql);
2923
        if (Database::num_rows($result)) {
2924
            $row = Database::fetch_array($result, 'ASSOC');
2925
2926
            return $row['count'] > 0;
2927
        }
2928
2929
        return false;
2930
    }
2931
2932
    /**
2933
     * @param int    $filter
2934
     * @param string $view
2935
     *
2936
     * @return string
2937
     */
2938
    public function displayActions($view, $filter = 0)
2939
    {
2940
        $courseInfo = api_get_course_info();
2941
        $groupInfo = GroupManager::get_group_properties(api_get_group_id());
2942
        $groupIid = isset($groupInfo['iid']) ? $groupInfo['iid'] : 0;
2943
2944
        $courseCondition = '';
2945
        if (!empty($courseInfo)) {
2946
            $courseCondition = api_get_cidreq();
2947
        }
2948
2949
        $actionsLeft = '';
2950
        $actionsLeft .= "<a href='".api_get_path(WEB_CODE_PATH)."calendar/agenda_js.php?type={$this->type}&".$courseCondition."'>".
2951
            Display::return_icon(
2952
                'calendar.png',
2953
                get_lang('Calendar'),
2954
                '',
2955
                ICON_SIZE_MEDIUM
2956
            )."</a>";
2957
2958
        $actionsLeft .= "<a href='".api_get_path(WEB_CODE_PATH)."calendar/agenda_list.php?type={$this->type}&".$courseCondition."'>".
2959
            Display::return_icon(
2960
                'week.png',
2961
                get_lang('AgendaList'),
2962
                '',
2963
                ICON_SIZE_MEDIUM
2964
            )."</a>";
2965
2966
        $form = '';
2967
        if (api_is_allowed_to_edit(false, true) ||
2968
            (api_get_course_setting('allow_user_edit_agenda') == '1' &&
2969
                !api_is_anonymous()) &&
2970
            api_is_allowed_to_session_edit(false, true) ||
2971
            (GroupManager::user_has_access(
2972
                api_get_user_id(),
2973
                $groupIid,
2974
                GroupManager::GROUP_TOOL_CALENDAR
2975
            ) &&
2976
            GroupManager::is_tutor_of_group(api_get_user_id(), $groupInfo))
2977
        ) {
2978
            $actionsLeft .= Display::url(
2979
                Display::return_icon(
2980
                    'new_event.png',
2981
                    get_lang('AgendaAdd'),
2982
                    '',
2983
                    ICON_SIZE_MEDIUM
2984
                ),
2985
                api_get_path(WEB_CODE_PATH)."calendar/agenda.php?".api_get_cidreq()."&action=add&type=".$this->type
2986
            );
2987
2988
            $actionsLeft .= Display::url(
2989
                Display::return_icon(
2990
                    'import_calendar.png',
2991
                    get_lang('ICalFileImport'),
2992
                    '',
2993
                    ICON_SIZE_MEDIUM
2994
                ),
2995
                api_get_path(WEB_CODE_PATH)."calendar/agenda.php?".api_get_cidreq()."&action=importical&type=".$this->type
2996
            );
2997
2998
            if ($this->type === 'course') {
2999
                if (!isset($_GET['action'])) {
3000
                    $form = new FormValidator(
3001
                        'form-search',
3002
                        'post',
3003
                        '',
3004
                        '',
3005
                        [],
3006
                        FormValidator::LAYOUT_INLINE
3007
                    );
3008
                    $attributes = [
3009
                        'multiple' => false,
3010
                        'id' => 'select_form_id_search',
3011
                    ];
3012
                    $selectedValues = $this->parseAgendaFilter($filter);
3013
                    $this->showToForm($form, $selectedValues, $attributes);
3014
                    $form = $form->returnForm();
3015
                }
3016
            }
3017
        }
3018
3019
        if (api_is_platform_admin() ||
3020
            api_is_teacher() ||
3021
            api_is_student_boss() ||
3022
            api_is_drh() ||
3023
            api_is_session_admin() ||
3024
            api_is_coach()
3025
        ) {
3026
            if ($this->type == 'personal') {
3027
                $form = null;
3028
                if (!isset($_GET['action'])) {
3029
                    $form = new FormValidator(
3030
                        'form-search',
3031
                        'get',
3032
                        api_get_self().'?type=personal&',
3033
                        '',
3034
                        [],
3035
                        FormValidator::LAYOUT_INLINE
3036
                    );
3037
3038
                    if (api_is_drh()) {
3039
                        $sessionList = SessionManager::get_sessions_followed_by_drh(
3040
                            api_get_user_id()
3041
                        );
3042
                        if (!empty($sessionList)) {
3043
                            $sessions = [];
3044
                            foreach ($sessionList as $sessionItem) {
3045
                                $sessions[$sessionItem['id']] = strip_tags($sessionItem['name']);
3046
                            }
3047
                        }
3048
                    } else {
3049
                        $sessions = SessionManager::get_sessions_by_user(
3050
                            api_get_user_id()
3051
                        );
3052
                        $sessions = array_column(
3053
                            $sessions,
3054
                            'session_name',
3055
                            'session_id'
3056
                        );
3057
                    }
3058
                    $form->addHidden('type', 'personal');
3059
                    $sessions = ['0' => get_lang('SelectAnOption')] + $sessions;
3060
3061
                    $form->addSelect(
3062
                        'session_id',
3063
                        get_lang('Session'),
3064
                        $sessions,
3065
                        ['id' => 'session_id', 'onchange' => 'submit();']
3066
                    );
3067
3068
                    $form->addButtonReset(get_lang('Reset'));
3069
                    $form = $form->returnForm();
3070
                }
3071
            }
3072
        }
3073
3074
        $actionsRight = '';
3075
        if ($view == 'calendar') {
3076
            $actionsRight .= $form;
3077
        }
3078
3079
        $toolbar = Display::toolbarAction(
3080
            'toolbar-agenda',
3081
            [$actionsLeft, $actionsRight]
3082
        );
3083
3084
        return $toolbar;
3085
    }
3086
3087
    /**
3088
     * @return FormValidator
3089
     */
3090
    public function getImportCalendarForm()
3091
    {
3092
        $form = new FormValidator(
3093
            'frm_import_ical',
3094
            'post',
3095
            api_get_self().'?action=importical&type='.$this->type,
3096
            ['enctype' => 'multipart/form-data']
3097
        );
3098
        $form->addElement('header', get_lang('ICalFileImport'));
3099
        $form->addElement('file', 'ical_import', get_lang('ICalFileImport'));
3100
        $form->addRule(
3101
            'ical_import',
3102
            get_lang('ThisFieldIsRequired'),
3103
            'required'
3104
        );
3105
        $form->addButtonImport(get_lang('Import'), 'ical_submit');
3106
3107
        return $form;
3108
    }
3109
3110
    /**
3111
     * @param array $courseInfo
3112
     * @param $file
3113
     *
3114
     * @return false|string
3115
     */
3116
    public function importEventFile($courseInfo, $file)
3117
    {
3118
        $charset = api_get_system_encoding();
3119
        $filepath = api_get_path(SYS_ARCHIVE_PATH).$file['name'];
3120
        $messages = [];
3121
3122
        if (!@move_uploaded_file($file['tmp_name'], $filepath)) {
3123
            error_log(
3124
                'Problem moving uploaded file: '.$file['error'].' in '.__FILE__.' line '.__LINE__
3125
            );
3126
3127
            return false;
3128
        }
3129
3130
        $data = file_get_contents($filepath);
3131
3132
        $trans = [
3133
            'DAILY' => 'daily',
3134
            'WEEKLY' => 'weekly',
3135
            'MONTHLY' => 'monthlyByDate',
3136
            'YEARLY' => 'yearly',
3137
        ];
3138
        $sentTo = ['everyone' => true];
3139
        $calendar = Sabre\VObject\Reader::read($data);
3140
        $currentTimeZone = api_get_timezone();
3141
        if (!empty($calendar->VEVENT)) {
3142
            foreach ($calendar->VEVENT as $event) {
3143
                $start = $event->DTSTART->getDateTime();
3144
                $end = $event->DTEND->getDateTime();
3145
                //Sabre\VObject\DateTimeParser::parseDateTime(string $dt, \Sabre\VObject\DateTimeZone $tz)
3146
3147
                $startDateTime = api_get_local_time(
3148
                    $start->format('Y-m-d H:i:s'),
3149
                    $currentTimeZone,
3150
                    $start->format('e')
3151
                );
3152
                $endDateTime = api_get_local_time(
3153
                    $end->format('Y-m-d H:i'),
3154
                    $currentTimeZone,
3155
                    $end->format('e')
3156
                );
3157
                $title = api_convert_encoding(
3158
                    (string) $event->summary,
3159
                    $charset,
3160
                    'UTF-8'
3161
                );
3162
                $description = api_convert_encoding(
3163
                    (string) $event->description,
3164
                    $charset,
3165
                    'UTF-8'
3166
                );
3167
3168
                $id = $this->addEvent(
3169
                    $startDateTime,
3170
                    $endDateTime,
3171
                    'false',
3172
                    $title,
3173
                    $description,
3174
                    $sentTo
3175
                );
3176
3177
                $messages[] = " $title - ".$startDateTime." - ".$endDateTime;
3178
3179
                //$attendee = (string)$event->attendee;
3180
                /** @var Sabre\VObject\Property\ICalendar\Recur $repeat */
3181
                $repeat = $event->RRULE;
3182
                if ($id && !empty($repeat)) {
3183
                    $repeat = $repeat->getParts();
3184
                    $freq = $trans[$repeat['FREQ']];
3185
3186
                    if (isset($repeat['UNTIL']) && !empty($repeat['UNTIL'])) {
3187
                        // Check if datetime or just date (strlen == 8)
3188
                        if (strlen($repeat['UNTIL']) == 8) {
3189
                            // Fix the datetime format to avoid exception in the next step
3190
                            $repeat['UNTIL'] .= 'T000000';
3191
                        }
3192
                        $until = Sabre\VObject\DateTimeParser::parseDateTime(
3193
                            $repeat['UNTIL'],
3194
                            new DateTimeZone($currentTimeZone)
3195
                        );
3196
                        $until = $until->format('Y-m-d H:i:s');
3197
                        $this->addRepeatedItem(
3198
                            $id,
3199
                            $freq,
3200
                            $until,
3201
                            $sentTo
3202
                        );
3203
                    }
3204
3205
                    if (!empty($repeat['COUNT'])) {
3206
                        /*$count = $repeat['COUNT'];
3207
                        $interval = $repeat['INTERVAL'];
3208
                        $endDate = null;
3209
                        switch($freq) {
3210
                            case 'daily':
3211
                                $start = api_strtotime($startDateTime);
3212
                                $date = new DateTime($startDateTime);
3213
                                $days = $count * $interval;
3214
                                var_dump($days);
3215
                                $date->add(new DateInterval("P".$days."D"));
3216
                                $endDate = $date->format('Y-m-d H:i');
3217
                                //$endDate = $count *
3218
                                for ($i = 0; $i < $count; $i++) {
3219
                                    $days = 86400 * 7
3220
                                }
3221
                            }
3222
                        }*/
3223
                        //$res = agenda_add_repeat_item($courseInfo, $id, $freq, $count, $attendee);
3224
                        /*$this->addRepeatedItem(
3225
                            $id,
3226
                            $freq,
3227
                            $endDate,
3228
                            $sentTo
3229
                        );*/
3230
                    }
3231
                }
3232
            }
3233
        }
3234
3235
        if (!empty($messages)) {
3236
            $messages = implode('<br /> ', $messages);
3237
        } else {
3238
            $messages = get_lang('NoAgendaItems');
3239
        }
3240
3241
        return $messages;
3242
    }
3243
3244
    /**
3245
     * Parse filter turns USER:12 to ['users' => [12])] or G:1 ['groups' => [1]].
3246
     *
3247
     * @param int $filter
3248
     *
3249
     * @return array
3250
     */
3251
    public function parseAgendaFilter($filter)
3252
    {
3253
        $everyone = false;
3254
        $groupId = null;
3255
        $userId = null;
3256
3257
        if ($filter == 'everyone') {
3258
            $everyone = true;
3259
        } else {
3260
            if (substr($filter, 0, 1) == 'G') {
3261
                $groupId = str_replace('GROUP:', '', $filter);
3262
            } else {
3263
                $userId = str_replace('USER:', '', $filter);
3264
            }
3265
        }
3266
        if (empty($userId) && empty($groupId)) {
3267
            $everyone = true;
3268
        }
3269
3270
        return [
3271
            'everyone' => $everyone,
3272
            'users' => [$userId],
3273
            'groups' => [$groupId],
3274
        ];
3275
    }
3276
3277
    /**
3278
     *    This function retrieves all the agenda items of all the courses the user is subscribed to.
3279
     */
3280
    public static function get_myagendaitems(
3281
        $user_id,
3282
        $courses_dbs,
3283
        $month,
3284
        $year
3285
    ) {
3286
        $user_id = intval($user_id);
3287
3288
        $items = [];
3289
        $my_list = [];
3290
3291
        // get agenda-items for every course
3292
        foreach ($courses_dbs as $key => $array_course_info) {
3293
            //databases of the courses
3294
            $TABLEAGENDA = Database::get_course_table(TABLE_AGENDA);
3295
            $TABLE_ITEMPROPERTY = Database::get_course_table(
3296
                TABLE_ITEM_PROPERTY
3297
            );
3298
3299
            $group_memberships = GroupManager::get_group_ids(
3300
                $array_course_info['real_id'],
3301
                $user_id
3302
            );
3303
            $course_user_status = CourseManager::getUserInCourseStatus(
3304
                $user_id,
3305
                $array_course_info['real_id']
3306
            );
3307
            // if the user is administrator of that course we show all the agenda items
3308
            if ($course_user_status == '1') {
3309
                //echo "course admin";
3310
                $sqlquery = "SELECT DISTINCT agenda.*, ip.visibility, ip.to_group_id, ip.insert_user_id, ip.ref
3311
							FROM ".$TABLEAGENDA." agenda,
3312
								 ".$TABLE_ITEMPROPERTY." ip
3313
							WHERE agenda.id = ip.ref
3314
							AND MONTH(agenda.start_date)='".$month."'
3315
							AND YEAR(agenda.start_date)='".$year."'
3316
							AND ip.tool='".TOOL_CALENDAR_EVENT."'
3317
							AND ip.visibility='1'
3318
							GROUP BY agenda.id
3319
							ORDER BY start_date ";
3320
            } else {
3321
                // if the user is not an administrator of that course
3322
                if (is_array($group_memberships) && count(
3323
                        $group_memberships
3324
                    ) > 0
3325
                ) {
3326
                    $sqlquery = "SELECT	agenda.*, ip.visibility, ip.to_group_id, ip.insert_user_id, ip.ref
3327
								FROM ".$TABLEAGENDA." agenda,
3328
									".$TABLE_ITEMPROPERTY." ip
3329
								WHERE agenda.id = ip.ref
3330
								AND MONTH(agenda.start_date)='".$month."'
3331
								AND YEAR(agenda.start_date)='".$year."'
3332
								AND ip.tool='".TOOL_CALENDAR_EVENT."'
3333
								AND	( ip.to_user_id='".$user_id."' OR (ip.to_group_id IS NULL OR ip.to_group_id IN (0, ".implode(
3334
                            ", ",
3335
                            $group_memberships
3336
                        ).")) )
3337
								AND ip.visibility='1'
3338
								ORDER BY start_date ";
3339
                } else {
3340
                    $sqlquery = "SELECT agenda.*, ip.visibility, ip.to_group_id, ip.insert_user_id, ip.ref
3341
								FROM ".$TABLEAGENDA." agenda,
3342
									".$TABLE_ITEMPROPERTY." ip
3343
								WHERE agenda.id = ip.ref
3344
								AND MONTH(agenda.start_date)='".$month."'
3345
								AND YEAR(agenda.start_date)='".$year."'
3346
								AND ip.tool='".TOOL_CALENDAR_EVENT."'
3347
								AND ( ip.to_user_id='".$user_id."' OR ip.to_group_id='0' OR ip.to_group_id IS NULL)
3348
								AND ip.visibility='1'
3349
								ORDER BY start_date ";
3350
                }
3351
            }
3352
            $result = Database::query($sqlquery);
3353
3354
            while ($item = Database::fetch_array($result, 'ASSOC')) {
3355
                $agendaday = -1;
3356
                if (!empty($item['start_date'])) {
3357
                    $item['start_date'] = api_get_local_time(
3358
                        $item['start_date']
3359
                    );
3360
                    $item['start_date_tms'] = api_strtotime(
3361
                        $item['start_date']
3362
                    );
3363
                    $agendaday = date("j", $item['start_date_tms']);
3364
                }
3365
                if (!empty($item['end_date'])) {
3366
                    $item['end_date'] = api_get_local_time($item['end_date']);
3367
                }
3368
3369
                $url = api_get_path(
3370
                        WEB_CODE_PATH
3371
                    )."calendar/agenda.php?cidReq=".urlencode(
3372
                        $array_course_info["code"]
3373
                    )."&day=$agendaday&month=$month&year=$year#$agendaday";
3374
3375
                $item['url'] = $url;
3376
                $item['course_name'] = $array_course_info['title'];
3377
                $item['calendar_type'] = 'course';
3378
                $item['course_id'] = $array_course_info['course_id'];
3379
3380
                $my_list[$agendaday][] = $item;
3381
            }
3382
        }
3383
3384
        // sorting by hour for every day
3385
        $agendaitems = [];
3386
        foreach ($items as $agendaday => $tmpitems) {
3387
            if (!isset($agendaitems[$agendaday])) {
3388
                $agendaitems[$agendaday] = '';
3389
            }
3390
            sort($tmpitems);
3391
            foreach ($tmpitems as $val) {
3392
                $agendaitems[$agendaday] .= $val;
3393
            }
3394
        }
3395
3396
        return $my_list;
3397
    }
3398
3399
    /**
3400
     * This function retrieves one personal agenda item returns it.
3401
     *
3402
     * @param    array    The array containing existing events. We add to this array.
3403
     * @param    int        Day
3404
     * @param    int        Month
3405
     * @param    int        Year (4 digits)
3406
     * @param    int        Week number
3407
     * @param    string    Type of view (month_view, week_view, day_view)
3408
     *
3409
     * @return array The results of the database query, or null if not found
3410
     */
3411
    public static function get_global_agenda_items(
3412
        $agendaitems,
3413
        $day = "",
3414
        $month = "",
3415
        $year = "",
3416
        $week = "",
3417
        $type
3418
    ) {
3419
        $tbl_global_agenda = Database::get_main_table(
3420
            TABLE_MAIN_SYSTEM_CALENDAR
3421
        );
3422
        $month = intval($month);
3423
        $year = intval($year);
3424
        $week = intval($week);
3425
        $day = intval($day);
3426
        // 1. creating the SQL statement for getting the personal agenda items in MONTH view
3427
3428
        $current_access_url_id = api_get_current_access_url_id();
3429
3430
        if ($type == "month_view" or $type == "") {
3431
            // We are in month view
3432
            $sql = "SELECT * FROM ".$tbl_global_agenda." WHERE MONTH(start_date) = ".$month." AND YEAR(start_date) = ".$year."  AND access_url_id = $current_access_url_id ORDER BY start_date ASC";
3433
        }
3434
        // 2. creating the SQL statement for getting the personal agenda items in WEEK view
3435
        if ($type == "week_view") { // we are in week view
3436
            $start_end_day_of_week = self::calculate_start_end_of_week(
3437
                $week,
3438
                $year
3439
            );
3440
            $start_day = $start_end_day_of_week['start']['day'];
3441
            $start_month = $start_end_day_of_week['start']['month'];
3442
            $start_year = $start_end_day_of_week['start']['year'];
3443
            $end_day = $start_end_day_of_week['end']['day'];
3444
            $end_month = $start_end_day_of_week['end']['month'];
3445
            $end_year = $start_end_day_of_week['end']['year'];
3446
            // in sql statements you have to use year-month-day for date calculations
3447
            $start_filter = $start_year."-".$start_month."-".$start_day." 00:00:00";
3448
            $start_filter = api_get_utc_datetime($start_filter);
3449
3450
            $end_filter = $end_year."-".$end_month."-".$end_day." 23:59:59";
3451
            $end_filter = api_get_utc_datetime($end_filter);
3452
            $sql = " SELECT * FROM ".$tbl_global_agenda." WHERE start_date>='".$start_filter."' AND start_date<='".$end_filter."' AND  access_url_id = $current_access_url_id ";
3453
        }
3454
        // 3. creating the SQL statement for getting the personal agenda items in DAY view
3455
        if ($type == "day_view") { // we are in day view
3456
            // we could use mysql date() function but this is only available from 4.1 and higher
3457
            $start_filter = $year."-".$month."-".$day." 00:00:00";
3458
            $start_filter = api_get_utc_datetime($start_filter);
3459
3460
            $end_filter = $year."-".$month."-".$day." 23:59:59";
3461
            $end_filter = api_get_utc_datetime($end_filter);
3462
            $sql = " SELECT * FROM ".$tbl_global_agenda." WHERE start_date>='".$start_filter."' AND start_date<='".$end_filter."'  AND  access_url_id = $current_access_url_id";
3463
        }
3464
3465
        $result = Database::query($sql);
3466
3467
        while ($item = Database::fetch_array($result)) {
3468
            if (!empty($item['start_date'])) {
3469
                $item['start_date'] = api_get_local_time($item['start_date']);
3470
                $item['start_date_tms'] = api_strtotime($item['start_date']);
3471
            }
3472
            if (!empty($item['end_date'])) {
3473
                $item['end_date'] = api_get_local_time($item['end_date']);
3474
            }
3475
3476
            // we break the date field in the database into a date and a time part
3477
            $agenda_db_date = explode(" ", $item['start_date']);
3478
            $date = $agenda_db_date[0];
3479
            $time = $agenda_db_date[1];
3480
            // we divide the date part into a day, a month and a year
3481
            $agendadate = explode("-", $date);
3482
            $year = intval($agendadate[0]);
3483
            $month = intval($agendadate[1]);
3484
            $day = intval($agendadate[2]);
3485
            // we divide the time part into hour, minutes, seconds
3486
            $agendatime = explode(":", $time);
3487
            $hour = $agendatime[0];
3488
            $minute = $agendatime[1];
3489
            $second = $agendatime[2];
3490
3491
            if ($type == 'month_view') {
3492
                $item['calendar_type'] = 'global';
3493
                $agendaitems[$day][] = $item;
3494
                continue;
3495
            }
3496
3497
            $start_time = api_format_date(
3498
                $item['start_date'],
3499
                TIME_NO_SEC_FORMAT
3500
            );
3501
            $end_time = '';
3502
            if (!empty($item['end_date'])) {
3503
                $end_time = ' - '.api_format_date(
3504
                        $item['end_date'],
3505
                        DATE_TIME_FORMAT_LONG
3506
                    );
3507
            }
3508
3509
            // if the student has specified a course we a add a link to that course
3510
            if ($item['course'] != "") {
3511
                $url = api_get_path(
3512
                        WEB_CODE_PATH
3513
                    )."admin/agenda.php?cidReq=".urlencode(
3514
                        $item['course']
3515
                    )."&day=$day&month=$month&year=$year#$day"; // RH  //Patrick Cool: to highlight the relevant agenda item
3516
                $course_link = "<a href=\"$url\" title=\"".$item['course']."\">".$item['course']."</a>";
3517
            } else {
3518
                $course_link = "";
3519
            }
3520
            // Creating the array that will be returned. If we have week or month view we have an array with the date as the key
3521
            // if we have a day_view we use a half hour as index => key 33 = 16h30
3522
            if ($type !== "day_view") {
3523
                // This is the array construction for the WEEK or MONTH view
3524
                //Display the Agenda global in the tab agenda (administrator)
3525
                $agendaitems[$day] .= "<i>$start_time $end_time</i>&nbsp;-&nbsp;";
3526
                $agendaitems[$day] .= "<b>".get_lang('GlobalEvent')."</b>";
3527
                $agendaitems[$day] .= "<div>".$item['title']."</div><br>";
3528
            } else {
3529
                // this is the array construction for the DAY view
3530
                $halfhour = 2 * $agendatime['0'];
3531
                if ($agendatime['1'] >= '30') {
3532
                    $halfhour = $halfhour + 1;
3533
                }
3534
                if (!is_array($agendaitems[$halfhour])) {
3535
                    $content = $agendaitems[$halfhour];
3536
                }
3537
                $agendaitems[$halfhour] = $content."<div><i>$hour:$minute</i> <b>".get_lang(
3538
                        'GlobalEvent'
3539
                    ).":  </b>".$item['title']."</div>";
3540
            }
3541
        }
3542
3543
        return $agendaitems;
3544
    }
3545
3546
    /**
3547
     * This function retrieves all the personal agenda items and add them to the agenda items found by the other
3548
     * functions.
3549
     */
3550
    public static function get_personal_agenda_items(
3551
        $user_id,
3552
        $agendaitems,
3553
        $day = "",
3554
        $month = "",
3555
        $year = "",
3556
        $week = "",
3557
        $type
3558
    ) {
3559
        $tbl_personal_agenda = Database::get_main_table(TABLE_PERSONAL_AGENDA);
3560
        $user_id = intval($user_id);
3561
3562
        // 1. creating the SQL statement for getting the personal agenda items in MONTH view
3563
        if ($type == "month_view" or $type == "") {
3564
            // we are in month view
3565
            $sql = "SELECT * FROM ".$tbl_personal_agenda." WHERE user='".$user_id."' and MONTH(date)='".$month."' AND YEAR(date) = '".$year."'  ORDER BY date ASC";
3566
        }
3567
3568
        // 2. creating the SQL statement for getting the personal agenda items in WEEK view
3569
        // we are in week view
3570
        if ($type == "week_view") {
3571
            $start_end_day_of_week = self::calculate_start_end_of_week(
3572
                $week,
3573
                $year
3574
            );
3575
            $start_day = $start_end_day_of_week['start']['day'];
3576
            $start_month = $start_end_day_of_week['start']['month'];
3577
            $start_year = $start_end_day_of_week['start']['year'];
3578
            $end_day = $start_end_day_of_week['end']['day'];
3579
            $end_month = $start_end_day_of_week['end']['month'];
3580
            $end_year = $start_end_day_of_week['end']['year'];
3581
            // in sql statements you have to use year-month-day for date calculations
3582
            $start_filter = $start_year."-".$start_month."-".$start_day." 00:00:00";
3583
            $start_filter = api_get_utc_datetime($start_filter);
3584
            $end_filter = $end_year."-".$end_month."-".$end_day." 23:59:59";
3585
            $end_filter = api_get_utc_datetime($end_filter);
3586
            $sql = " SELECT * FROM ".$tbl_personal_agenda." WHERE user='".$user_id."' AND date>='".$start_filter."' AND date<='".$end_filter."'";
3587
        }
3588
        // 3. creating the SQL statement for getting the personal agenda items in DAY view
3589
        if ($type == "day_view") {
3590
            // we are in day view
3591
            // we could use mysql date() function but this is only available from 4.1 and higher
3592
            $start_filter = $year."-".$month."-".$day." 00:00:00";
3593
            $start_filter = api_get_utc_datetime($start_filter);
3594
            $end_filter = $year."-".$month."-".$day." 23:59:59";
3595
            $end_filter = api_get_utc_datetime($end_filter);
3596
            $sql = " SELECT * FROM ".$tbl_personal_agenda." WHERE user='".$user_id."' AND date>='".$start_filter."' AND date<='".$end_filter."'";
3597
        }
3598
3599
        $result = Database::query($sql);
3600
        while ($item = Database::fetch_array($result, 'ASSOC')) {
3601
            $time_minute = api_convert_and_format_date(
3602
                $item['date'],
3603
                TIME_NO_SEC_FORMAT
3604
            );
3605
            $item['date'] = api_get_local_time($item['date']);
3606
            $item['start_date_tms'] = api_strtotime($item['date']);
3607
            $item['content'] = $item['text'];
3608
3609
            // we break the date field in the database into a date and a time part
3610
            $agenda_db_date = explode(" ", $item['date']);
3611
            $date = $agenda_db_date[0];
3612
            $time = $agenda_db_date[1];
3613
            // we divide the date part into a day, a month and a year
3614
            $agendadate = explode("-", $item['date']);
3615
            $year = intval($agendadate[0]);
3616
            $month = intval($agendadate[1]);
3617
            $day = intval($agendadate[2]);
3618
            // we divide the time part into hour, minutes, seconds
3619
            $agendatime = explode(":", $time);
3620
3621
            $hour = $agendatime[0];
3622
            $minute = $agendatime[1];
3623
            $second = $agendatime[2];
3624
3625
            if ($type == 'month_view') {
3626
                $item['calendar_type'] = 'personal';
3627
                $item['start_date'] = $item['date'];
3628
                $agendaitems[$day][] = $item;
3629
                continue;
3630
            }
3631
3632
            // if the student has specified a course we a add a link to that course
3633
            if ($item['course'] != "") {
3634
                $url = api_get_path(
3635
                        WEB_CODE_PATH
3636
                    )."calendar/agenda.php?cidReq=".urlencode(
3637
                        $item['course']
3638
                    )."&day=$day&month=$month&year=$year#$day"; // RH  //Patrick Cool: to highlight the relevant agenda item
3639
                $course_link = "<a href=\"$url\" title=\"".$item['course']."\">".$item['course']."</a>";
3640
            } else {
3641
                $course_link = "";
3642
            }
3643
            // Creating the array that will be returned. If we have week or month view we have an array with the date as the key
3644
            // if we have a day_view we use a half hour as index => key 33 = 16h30
3645
            if ($type !== "day_view") {
3646
                // This is the array construction for the WEEK or MONTH view
3647
3648
                //Display events in agenda
3649
                $agendaitems[$day] .= "<div><i>$time_minute</i> $course_link <a href=\"myagenda.php?action=view&view=personal&day=$day&month=$month&year=$year&id=".$item['id']."#".$item['id']."\" class=\"personal_agenda\">".$item['title']."</a></div><br />";
3650
            } else {
3651
                // this is the array construction for the DAY view
3652
                $halfhour = 2 * $agendatime['0'];
3653
                if ($agendatime['1'] >= '30') {
3654
                    $halfhour = $halfhour + 1;
3655
                }
3656
3657
                //Display events by list
3658
                $agendaitems[$halfhour] .= "<div><i>$time_minute</i> $course_link <a href=\"myagenda.php?action=view&view=personal&day=$day&month=$month&year=$year&id=".$item['id']."#".$item['id']."\" class=\"personal_agenda\">".$item['title']."</a></div>";
3659
            }
3660
        }
3661
3662
        return $agendaitems;
3663
    }
3664
3665
    /**
3666
     * Show the monthcalender of the given month.
3667
     *
3668
     * @param    array    Agendaitems
3669
     * @param    int    Month number
3670
     * @param    int    Year number
3671
     * @param    array    Array of strings containing long week day names (deprecated, you can send an empty array
3672
     *                          instead)
3673
     * @param    string    The month name
3674
     */
3675
    public static function display_mymonthcalendar(
3676
        $user_id,
3677
        $agendaitems,
3678
        $month,
3679
        $year,
3680
        $weekdaynames = [],
3681
        $monthName,
3682
        $show_content = true
3683
    ) {
3684
        global $DaysShort, $course_path;
3685
        //Handle leap year
3686
        $numberofdays = [
3687
            0,
3688
            31,
3689
            28,
3690
            31,
3691
            30,
3692
            31,
3693
            30,
3694
            31,
3695
            31,
3696
            30,
3697
            31,
3698
            30,
3699
            31,
3700
        ];
3701
        if (($year % 400 == 0) or ($year % 4 == 0 and $year % 100 != 0)) {
3702
            $numberofdays[2] = 29;
3703
        }
3704
        //Get the first day of the month
3705
        $dayone = getdate(mktime(0, 0, 0, $month, 1, $year));
3706
        //Start the week on monday
3707
        $startdayofweek = $dayone['wday'] != 0 ? ($dayone['wday'] - 1) : 6;
3708
        $g_cc = (isset($_GET['courseCode']) ? $_GET['courseCode'] : '');
3709
3710
        $next_month = ($month == 1 ? 12 : $month - 1);
3711
        $prev_month = ($month == 12 ? 1 : $month + 1);
3712
3713
        $next_year = ($month == 1 ? $year - 1 : $year);
3714
        $prev_year = ($month == 12 ? $year + 1 : $year);
3715
3716
        if ($show_content) {
3717
            $back_url = Display::url(
3718
                get_lang('Previous'),
3719
                api_get_self()."?coursePath=".urlencode(
3720
                    $course_path
3721
                )."&courseCode=".Security::remove_XSS(
3722
                    $g_cc
3723
                )."&action=view&view=month&month=".$next_month."&year=".$next_year
3724
            );
3725
            $next_url = Display::url(
3726
                get_lang('Next'),
3727
                api_get_self()."?coursePath=".urlencode(
3728
                    $course_path
3729
                )."&courseCode=".Security::remove_XSS(
3730
                    $g_cc
3731
                )."&action=view&view=month&month=".$prev_month."&year=".$prev_year
3732
            );
3733
        } else {
3734
            $back_url = Display::url(
3735
                get_lang('Previous'),
3736
                '',
3737
                [
3738
                    'onclick' => "load_calendar('".$user_id."','".$next_month."', '".$next_year."'); ",
3739
                    'class' => 'btn ui-button ui-widget ui-state-default',
3740
                ]
3741
            );
3742
            $next_url = Display::url(
3743
                get_lang('Next'),
3744
                '',
3745
                [
3746
                    'onclick' => "load_calendar('".$user_id."','".$prev_month."', '".$prev_year."'); ",
3747
                    'class' => 'pull-right btn ui-button ui-widget ui-state-default',
3748
                ]
3749
            );
3750
        }
3751
        $html = '';
3752
        $html .= '<div class="actions">';
3753
        $html .= '<div class="row">';
3754
        $html .= '<div class="col-md-4">'.$back_url.'</div>';
3755
        $html .= '<div class="col-md-4"><p class="agenda-title text-center">'.$monthName." ".$year.'</p></div>';
3756
        $html .= '<div class="col-md-4">'.$next_url.'</div>';
3757
        $html .= '</div>';
3758
        $html .= '</div>';
3759
        $html .= '<table id="agenda_list2" class="table table-bordered">';
3760
        $html .= '<tr>';
3761
        for ($ii = 1; $ii < 8; $ii++) {
3762
            $html .= '<td class="weekdays">'.$DaysShort[$ii % 7].'</td>';
3763
        }
3764
        $html .= '</tr>';
3765
3766
        $curday = -1;
3767
        $today = getdate();
3768
        while ($curday <= $numberofdays[$month]) {
3769
            $html .= "<tr>";
3770
            for ($ii = 0; $ii < 7; $ii++) {
3771
                if (($curday == -1) && ($ii == $startdayofweek)) {
3772
                    $curday = 1;
3773
                }
3774
                if (($curday > 0) && ($curday <= $numberofdays[$month])) {
3775
                    $bgcolor = $class = 'class="days_week"';
3776
                    $dayheader = Display::div(
3777
                        $curday,
3778
                        ['class' => 'agenda_day']
3779
                    );
3780
                    if (($curday == $today['mday']) && ($year == $today['year']) && ($month == $today['mon'])) {
3781
                        $class = "class=\"days_today\" style=\"width:10%;\"";
3782
                    }
3783
3784
                    $html .= "<td ".$class.">".$dayheader;
3785
3786
                    if (!empty($agendaitems[$curday])) {
3787
                        $items = $agendaitems[$curday];
3788
                        $items = msort($items, 'start_date_tms');
3789
3790
                        foreach ($items as $value) {
3791
                            $value['title'] = Security::remove_XSS(
3792
                                $value['title']
3793
                            );
3794
                            $start_time = api_format_date(
3795
                                $value['start_date'],
3796
                                TIME_NO_SEC_FORMAT
3797
                            );
3798
                            $end_time = '';
3799
3800
                            if (!empty($value['end_date'])) {
3801
                                $end_time = '-&nbsp;<i>'.api_format_date(
3802
                                        $value['end_date'],
3803
                                        DATE_TIME_FORMAT_LONG
3804
                                    ).'</i>';
3805
                            }
3806
                            $complete_time = '<i>'.api_format_date(
3807
                                    $value['start_date'],
3808
                                    DATE_TIME_FORMAT_LONG
3809
                                ).'</i>&nbsp;'.$end_time;
3810
                            $time = '<i>'.$start_time.'</i>';
3811
3812
                            switch ($value['calendar_type']) {
3813
                                case 'personal':
3814
                                    $bg_color = '#D0E7F4';
3815
                                    $icon = Display::return_icon(
3816
                                        'user.png',
3817
                                        get_lang('MyAgenda'),
3818
                                        [],
3819
                                        ICON_SIZE_SMALL
3820
                                    );
3821
                                    break;
3822
                                case 'global':
3823
                                    $bg_color = '#FFBC89';
3824
                                    $icon = Display::return_icon(
3825
                                        'view_remove.png',
3826
                                        get_lang('GlobalEvent'),
3827
                                        [],
3828
                                        ICON_SIZE_SMALL
3829
                                    );
3830
                                    break;
3831
                                case 'course':
3832
                                    $bg_color = '#CAFFAA';
3833
                                    $icon_name = 'course.png';
3834
                                    if (!empty($value['session_id'])) {
3835
                                        $icon_name = 'session.png';
3836
                                    }
3837
                                    if ($show_content) {
3838
                                        $icon = Display::url(
3839
                                            Display::return_icon(
3840
                                                $icon_name,
3841
                                                $value['course_name'].' '.get_lang(
3842
                                                    'Course'
3843
                                                ),
3844
                                                [],
3845
                                                ICON_SIZE_SMALL
3846
                                            ),
3847
                                            $value['url']
3848
                                        );
3849
                                    } else {
3850
                                        $icon = Display::return_icon(
3851
                                            $icon_name,
3852
                                            $value['course_name'].' '.get_lang(
3853
                                                'Course'
3854
                                            ),
3855
                                            [],
3856
                                            ICON_SIZE_SMALL
3857
                                        );
3858
                                    }
3859
                                    break;
3860
                                default:
3861
                                    break;
3862
                            }
3863
3864
                            $result = '<div class="rounded_div_agenda" style="background-color:'.$bg_color.';">';
3865
3866
                            if ($show_content) {
3867
                                //Setting a personal event to green
3868
                                $icon = Display::div(
3869
                                    $icon,
3870
                                    ['style' => 'float:right']
3871
                                );
3872
3873
                                $link = $value['calendar_type'].'_'.$value['id'].'_'.$value['course_id'].'_'.$value['session_id'];
3874
3875
                                //Link to bubble
3876
                                $url = Display::url(
3877
                                    cut($value['title'], 40),
3878
                                    '#',
3879
                                    ['id' => $link, 'class' => 'opener']
3880
                                );
3881
                                $result .= $time.' '.$icon.' '.Display::div(
3882
                                        $url
3883
                                    );
3884
3885
                                //Hidden content
3886
                                $content = Display::div(
3887
                                    $icon.Display::tag(
3888
                                        'h2',
3889
                                        $value['course_name']
3890
                                    ).'<hr />'.Display::tag(
3891
                                        'h3',
3892
                                        $value['title']
3893
                                    ).$complete_time.'<hr />'.Security::remove_XSS(
3894
                                        $value['content']
3895
                                    )
3896
                                );
3897
3898
                                //Main div
3899
                                $result .= Display::div(
3900
                                    $content,
3901
                                    [
3902
                                        'id' => 'main_'.$link,
3903
                                        'class' => 'dialog',
3904
                                        'style' => 'display:none',
3905
                                    ]
3906
                                );
3907
                                $result .= '</div>';
3908
                                $html .= $result;
3909
                            } else {
3910
                                $html .= $result .= $icon.'</div>';
3911
                            }
3912
                        }
3913
                    }
3914
                    $html .= "</td>";
3915
                    $curday++;
3916
                } else {
3917
                    $html .= "<td></td>";
3918
                }
3919
            }
3920
            $html .= "</tr>";
3921
        }
3922
        $html .= "</table>";
3923
        echo $html;
3924
    }
3925
3926
    /**
3927
     * Get personal agenda items between two dates (=all events from all registered courses).
3928
     *
3929
     * @param int $user_id user ID of the user
3930
     * @param    string    Optional start date in datetime format (if no start date is given, uses today)
3931
     * @param    string    Optional end date in datetime format (if no date is given, uses one year from now)
3932
     *
3933
     * @return array array of events ordered by start date, in
3934
     *               [0]('datestart','dateend','title'),[1]('datestart','dateend','title','link','coursetitle') format,
3935
     *               where datestart and dateend are in yyyyMMddhhmmss format
3936
     *
3937
     * @deprecated use agenda events
3938
     */
3939
    public static function get_personal_agenda_items_between_dates(
3940
        $user_id,
3941
        $date_start = '',
3942
        $date_end = ''
3943
    ) {
3944
        $items = [];
3945
        if ($user_id != strval(intval($user_id))) {
3946
            return $items;
3947
        }
3948
        if (empty($date_start)) {
3949
            $date_start = date('Y-m-d H:i:s');
3950
        }
3951
        if (empty($date_end)) {
3952
            $date_end = date(
3953
                'Y-m-d H:i:s',
3954
                mktime(0, 0, 0, date("m"), date("d"), date("Y") + 1)
3955
            );
3956
        }
3957
        $expr = '/\d{4}-\d{2}-\d{2}\ \d{2}:\d{2}:\d{2}/';
3958
        if (!preg_match($expr, $date_start)) {
3959
            return $items;
3960
        }
3961
        if (!preg_match($expr, $date_end)) {
3962
            return $items;
3963
        }
3964
3965
        // get agenda-items for every course
3966
        $courses = api_get_user_courses($user_id, false);
3967
        foreach ($courses as $id => $course) {
3968
            $c = api_get_course_info_by_id($course['real_id']);
3969
            //databases of the courses
3970
            $t_a = Database::get_course_table(TABLE_AGENDA, $course['db']);
3971
            $t_ip = Database::get_course_table(
3972
                TABLE_ITEM_PROPERTY,
3973
                $course['db']
3974
            );
3975
            // get the groups to which the user belong
3976
            $group_memberships = GroupManager:: get_group_ids(
3977
                $course['db'],
3978
                $user_id
3979
            );
3980
            // if the user is administrator of that course we show all the agenda items
3981
            if ($course['status'] == '1') {
3982
                //echo "course admin";
3983
                $sqlquery = "SELECT ".
3984
                    " DISTINCT agenda.*, ip.visibility, ip.to_group_id, ip.insert_user_id, ip.ref ".
3985
                    " FROM ".$t_a." agenda, ".
3986
                    $t_ip." ip ".
3987
                    " WHERE agenda.id = ip.ref ".
3988
                    " AND agenda.start_date>='$date_start' ".
3989
                    " AND agenda.end_date<='$date_end' ".
3990
                    " AND ip.tool='".TOOL_CALENDAR_EVENT."' ".
3991
                    " AND ip.visibility='1' ".
3992
                    " GROUP BY agenda.id ".
3993
                    " ORDER BY start_date ";
3994
            } else {
3995
                // if the user is not an administrator of that course, then...
3996
                if (is_array($group_memberships) && count(
3997
                        $group_memberships
3998
                    ) > 0
3999
                ) {
4000
                    $sqlquery = "SELECT ".
4001
                        "DISTINCT agenda.*, ip.visibility, ip.to_group_id, ip.insert_user_id, ip.ref ".
4002
                        " FROM ".$t_a." agenda, ".
4003
                        $t_ip." ip ".
4004
                        " WHERE agenda.id = ip.ref ".
4005
                        " AND agenda.start_date>='$date_start' ".
4006
                        " AND agenda.end_date<='$date_end' ".
4007
                        " AND ip.tool='".TOOL_CALENDAR_EVENT."' ".
4008
                        " AND	( ip.to_user_id='".$user_id."' OR (ip.to_group_id IS NULL OR ip.to_group_id IN (0, ".implode(
4009
                            ", ",
4010
                            $group_memberships
4011
                        ).")) ) ".
4012
                        " AND ip.visibility='1' ".
4013
                        " ORDER BY start_date ";
4014
                } else {
4015
                    $sqlquery = "SELECT ".
4016
                        "DISTINCT agenda.*, ip.visibility, ip.to_group_id, ip.insert_user_id, ip.ref ".
4017
                        " FROM ".$t_a." agenda, ".
4018
                        $t_ip." ip ".
4019
                        " WHERE agenda.id = ip.ref ".
4020
                        " AND agenda.start_date>='$date_start' ".
4021
                        " AND agenda.end_date<='$date_end' ".
4022
                        " AND ip.tool='".TOOL_CALENDAR_EVENT."' ".
4023
                        " AND ( ip.to_user_id='".$user_id."' OR ip.to_group_id='0' OR ip.to_group_id IS NULL) ".
4024
                        " AND ip.visibility='1' ".
4025
                        " ORDER BY start_date ";
4026
                }
4027
            }
4028
4029
            $result = Database::query($sqlquery);
4030
            while ($item = Database::fetch_array($result)) {
4031
                $agendaday = date("j", strtotime($item['start_date']));
4032
                $month = date("n", strtotime($item['start_date']));
4033
                $year = date("Y", strtotime($item['start_date']));
4034
                $URL = api_get_path(
4035
                        WEB_PATH
4036
                    )."main/calendar/agenda.php?cidReq=".urlencode(
4037
                        $course["code"]
4038
                    )."&day=$agendaday&month=$month&year=$year#$agendaday";
4039
                list($year, $month, $day, $hour, $min, $sec) = explode(
4040
                    '[-: ]',
4041
                    $item['start_date']
4042
                );
4043
                $start_date = $year.$month.$day.$hour.$min;
4044
                list($year, $month, $day, $hour, $min, $sec) = explode(
4045
                    '[-: ]',
4046
                    $item['end_date']
4047
                );
4048
                $end_date = $year.$month.$day.$hour.$min;
4049
4050
                $items[] = [
4051
                    'datestart' => $start_date,
4052
                    'dateend' => $end_date,
4053
                    'title' => $item['title'],
4054
                    'link' => $URL,
4055
                    'coursetitle' => $c['name'],
4056
                ];
4057
            }
4058
        }
4059
4060
        return $items;
4061
    }
4062
4063
    /**
4064
     * This function retrieves one personal agenda item returns it.
4065
     *
4066
     * @param int $id The agenda item ID
4067
     *
4068
     * @return array The results of the database query, or null if not found
4069
     */
4070
    public static function get_personal_agenda_item($id)
4071
    {
4072
        $table = Database::get_main_table(TABLE_PERSONAL_AGENDA);
4073
        $id = intval($id);
4074
        // make sure events of the personal agenda can only be seen by the user himself
4075
        $user = api_get_user_id();
4076
        $sql = " SELECT * FROM ".$table." WHERE id=".$id." AND user = ".$user;
4077
        $result = Database::query($sql);
4078
        if (Database::num_rows($result) == 1) {
4079
            $item = Database::fetch_array($result);
4080
        } else {
4081
            $item = null;
4082
        }
4083
4084
        return $item;
4085
    }
4086
4087
    /**
4088
     * This function calculates the startdate of the week (monday)
4089
     * and the enddate of the week (sunday)
4090
     * and returns it as an array.
4091
     */
4092
    public static function calculate_start_end_of_week($week_number, $year)
4093
    {
4094
        // determine the start and end date
4095
        // step 1: we calculate a timestamp for a day in this week
4096
        $random_day_in_week = mktime(
4097
                0,
4098
                0,
4099
                0,
4100
                1,
4101
                1,
4102
                $year
4103
            ) + ($week_number) * (7 * 24 * 60 * 60); // we calculate a random day in this week
4104
        // step 2: we which day this is (0=sunday, 1=monday, ...)
4105
        $number_day_in_week = date('w', $random_day_in_week);
4106
        // step 3: we calculate the timestamp of the monday of the week we are in
4107
        $start_timestamp = $random_day_in_week - (($number_day_in_week - 1) * 24 * 60 * 60);
4108
        // step 4: we calculate the timestamp of the sunday of the week we are in
4109
        $end_timestamp = $random_day_in_week + ((7 - $number_day_in_week + 1) * 24 * 60 * 60) - 3600;
4110
        // step 5: calculating the start_day, end_day, start_month, end_month, start_year, end_year
4111
        $start_day = date('j', $start_timestamp);
4112
        $start_month = date('n', $start_timestamp);
4113
        $start_year = date('Y', $start_timestamp);
4114
        $end_day = date('j', $end_timestamp);
4115
        $end_month = date('n', $end_timestamp);
4116
        $end_year = date('Y', $end_timestamp);
4117
        $start_end_array['start']['day'] = $start_day;
4118
        $start_end_array['start']['month'] = $start_month;
4119
        $start_end_array['start']['year'] = $start_year;
4120
        $start_end_array['end']['day'] = $end_day;
4121
        $start_end_array['end']['month'] = $end_month;
4122
        $start_end_array['end']['year'] = $end_year;
4123
4124
        return $start_end_array;
4125
    }
4126
4127
    /**
4128
     * @return bool
4129
     */
4130
    public function getIsAllowedToEdit()
4131
    {
4132
        return $this->isAllowedToEdit;
4133
    }
4134
4135
    /**
4136
     * @param bool $isAllowedToEdit
4137
     */
4138
    public function setIsAllowedToEdit($isAllowedToEdit)
4139
    {
4140
        $this->isAllowedToEdit = $isAllowedToEdit;
4141
    }
4142
4143
    /**
4144
     * Format needed for the Fullcalendar js lib.
4145
     *
4146
     * @param string $utcTime
4147
     *
4148
     * @return bool|string
4149
     */
4150
    public function formatEventDate($utcTime)
4151
    {
4152
        $utcTimeZone = new DateTimeZone('UTC');
4153
        $platformTimeZone = new DateTimeZone(api_get_timezone());
4154
4155
        $eventDate = new DateTime($utcTime, $utcTimeZone);
4156
        $eventDate->setTimezone($platformTimeZone);
4157
4158
        return $eventDate->format(DateTime::ISO8601);
4159
    }
4160
}
4161