Agenda::editEvent()   F
last analyzed

Complexity

Conditions 59
Paths 8536

Size

Total Lines 387
Code Lines 231

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 231
c 0
b 0
f 0
dl 0
loc 387
rs 0
cc 59
nc 8536
nop 23

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
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\AgendaEventInvitation;
6
use Chamilo\CoreBundle\Entity\AgendaEventInvitee;
7
use Chamilo\CoreBundle\Entity\AgendaEventSubscriber;
8
use Chamilo\CoreBundle\Entity\AgendaEventSubscription;
9
use Chamilo\CoreBundle\Entity\AgendaReminder;
10
use Chamilo\CoreBundle\Entity\PersonalAgenda;
11
use Chamilo\UserBundle\Entity\User;
12
13
/**
14
 * Class Agenda.
15
 *
16
 * @author: Julio Montoya <[email protected]>
17
 */
18
class Agenda
19
{
20
    public $events = [];
21
    /** @var string Current type */
22
    public $type = 'personal';
23
    public $types = ['personal', 'admin', 'course'];
24
    public $sessionId = 0;
25
    public $senderId;
26
    /** @var array */
27
    public $course;
28
    /** @var string */
29
    public $comment;
30
    public $eventStudentPublicationColor;
31
    /** @var array */
32
    private $sessionInfo;
33
    /** @var bool */
34
    private $isAllowedToEdit;
35
36
    /**
37
     * Constructor.
38
     *
39
     * @param string $type
40
     * @param int    $senderId  Optional The user sender ID
41
     * @param int    $courseId  Optional. The course ID
42
     * @param int    $sessionId Optional The session ID
43
     */
44
    public function __construct(
45
        $type,
46
        $senderId = 0,
47
        $courseId = 0,
48
        $sessionId = 0
49
    ) {
50
        // Table definitions
51
        $this->tbl_global_agenda = Database::get_main_table(TABLE_MAIN_SYSTEM_CALENDAR);
52
        $this->tbl_personal_agenda = Database::get_main_table(TABLE_PERSONAL_AGENDA);
53
        $this->tbl_course_agenda = Database::get_course_table(TABLE_AGENDA);
54
        $this->table_repeat = Database::get_course_table(TABLE_AGENDA_REPEAT);
55
56
        $this->setType($type);
57
        $this->setSenderId($senderId ?: api_get_user_id());
58
        $isAllowToEdit = false;
59
60
        switch ($type) {
61
            case 'course':
62
                $sessionId = $sessionId ?: api_get_session_id();
63
                $sessionInfo = api_get_session_info($sessionId);
64
                $this->setSessionId($sessionId);
65
                $this->setSessionInfo($sessionInfo);
66
67
                // Setting the course object if we are in a course
68
                $courseInfo = api_get_course_info_by_id($courseId);
69
                if (!empty($courseInfo)) {
70
                    $this->set_course($courseInfo);
71
                }
72
73
                // Check if teacher/admin rights.
74
                $isAllowToEdit = api_is_allowed_to_edit(false, true);
75
                // Check course setting.
76
                if (api_get_course_setting('allow_user_edit_agenda') == '1'
77
                    && api_is_allowed_in_course()
78
                ) {
79
                    $isAllowToEdit = true;
80
                }
81
82
                $groupId = api_get_group_id();
83
                if (!empty($groupId)) {
84
                    $groupInfo = GroupManager::get_group_properties($groupId);
85
                    $userHasAccess = GroupManager::user_has_access(
86
                        api_get_user_id(),
87
                        $groupInfo['iid'],
88
                        GroupManager::GROUP_TOOL_CALENDAR
89
                    );
90
                    $isTutor = GroupManager::is_tutor_of_group(
91
                        api_get_user_id(),
92
                        $groupInfo
93
                    );
94
95
                    $isGroupAccess = $userHasAccess || $isTutor;
96
                    $isAllowToEdit = false;
97
                    if ($isGroupAccess) {
98
                        $isAllowToEdit = true;
99
                    }
100
                }
101
102
                if (false === $isAllowToEdit && !empty($sessionId)) {
103
                    $allowDhrToEdit = api_get_configuration_value('allow_agenda_edit_for_hrm');
104
                    if ($allowDhrToEdit) {
105
                        $isHrm = SessionManager::isUserSubscribedAsHRM($sessionId, api_get_user_id());
106
                        if ($isHrm) {
107
                            $isAllowToEdit = true;
108
                        }
109
                    }
110
                }
111
                break;
112
            case 'admin':
113
                $isAllowToEdit = api_is_platform_admin();
114
                break;
115
            case 'personal':
116
                $isAllowToEdit = !api_is_anonymous();
117
                break;
118
        }
119
120
        $this->setIsAllowedToEdit($isAllowToEdit);
121
        $this->events = [];
122
        $agendaColors = array_merge(
123
            [
124
                'platform' => 'red', //red
125
                'course' => '#458B00', //green
126
                'group' => '#A0522D', //siena
127
                'session' => '#00496D', // kind of green
128
                'other_session' => '#999', // kind of green
129
                'personal' => 'steel blue', //steel blue
130
                'student_publication' => '#FF8C00', //DarkOrange
131
            ],
132
            api_get_configuration_value('agenda_colors') ?: []
133
        );
134
135
        // Event colors
136
        $this->event_platform_color = $agendaColors['platform'];
137
        $this->event_course_color = $agendaColors['course'];
138
        $this->event_group_color = $agendaColors['group'];
139
        $this->event_session_color = $agendaColors['session'];
140
        $this->eventOtherSessionColor = $agendaColors['other_session'];
141
        $this->event_personal_color = $agendaColors['personal'];
142
        $this->eventStudentPublicationColor = $agendaColors['student_publication'];
143
    }
144
145
    /**
146
     * @param int $senderId
147
     */
148
    public function setSenderId($senderId)
149
    {
150
        $this->senderId = (int) $senderId;
151
    }
152
153
    /**
154
     * @return int
155
     */
156
    public function getSenderId()
157
    {
158
        return $this->senderId;
159
    }
160
161
    /**
162
     * @param string $type can be 'personal', 'admin'  or  'course'
163
     */
164
    public function setType($type)
165
    {
166
        $type = (string) trim($type);
167
        $typeList = $this->getTypes();
168
        if (in_array($type, $typeList, true)) {
169
            $this->type = $type;
170
        }
171
    }
172
173
    /**
174
     * Returns the type previously set (and filtered) through setType
175
     * If setType() was not called, then type defaults to "personal" as
176
     * set in the class definition.
177
     */
178
    public function getType()
179
    {
180
        if (isset($this->type)) {
181
            return $this->type;
182
        }
183
    }
184
185
    /**
186
     * @param int $id
187
     */
188
    public function setSessionId($id)
189
    {
190
        $this->sessionId = (int) $id;
191
    }
192
193
    /**
194
     * @param array $sessionInfo
195
     */
196
    public function setSessionInfo($sessionInfo)
197
    {
198
        $this->sessionInfo = $sessionInfo;
199
    }
200
201
    /**
202
     * @return int $id
203
     */
204
    public function getSessionId()
205
    {
206
        return $this->sessionId;
207
    }
208
209
    /**
210
     * @param array $courseInfo
211
     */
212
    public function set_course($courseInfo)
213
    {
214
        $this->course = $courseInfo;
215
    }
216
217
    /**
218
     * @return array
219
     */
220
    public function getTypes()
221
    {
222
        return $this->types;
223
    }
224
225
    /**
226
     * Adds an event to the calendar.
227
     *
228
     * @param string $start                 datetime format: 2012-06-14 09:00:00 in local time
229
     * @param string $end                   datetime format: 2012-06-14 09:00:00 in local time
230
     * @param string $allDay                (true, false)
231
     * @param string $title
232
     * @param string $content
233
     * @param array  $usersToSend           array('everyone') or a list of user/group ids
234
     * @param bool   $addAsAnnouncement     event as a *course* announcement
235
     * @param int    $parentEventId
236
     * @param array  $attachmentArray       array of $_FILES['']
237
     * @param array  $attachmentCommentList
238
     * @param string $eventComment
239
     * @param string $color
240
     *
241
     * @return int
242
     */
243
    public function addEvent(
244
        $start,
245
        $end,
246
        $allDay,
247
        $title,
248
        $content,
249
        $usersToSend = [],
250
        $addAsAnnouncement = false,
251
        $parentEventId = null,
252
        $attachmentArray = [],
253
        $attachmentCommentList = [],
254
        $eventComment = null,
255
        $color = '',
256
        array $inviteesList = [],
257
        bool $isCollective = false,
258
        array $reminders = [],
259
        int $careerId = 0,
260
        int $promotionId = 0,
261
        int $subscriptionVisibility = 0,
262
        ?int $subscriptionItemId = null,
263
        int $maxSubscriptions = 0
264
    ) {
265
        $start = api_get_utc_datetime($start);
266
        $end = api_get_utc_datetime($end);
267
        $allDay = isset($allDay) && ($allDay === 'true' || $allDay == 1) ? 1 : 0;
268
        $id = null;
269
270
        $em = Database::getManager();
271
272
        switch ($this->type) {
273
            case 'personal':
274
                $attributes = [
275
                    'user' => api_get_user_id(),
276
                    'title' => $title,
277
                    'text' => Security::remove_XSS($content),
278
                    'date' => $start,
279
                    'enddate' => $end,
280
                    'all_day' => $allDay,
281
                    'color' => $color,
282
                ];
283
284
                $id = Database::insert(
285
                    $this->tbl_personal_agenda,
286
                    $attributes
287
                );
288
289
                if (api_get_configuration_value('agenda_collective_invitations')) {
290
                    Agenda::saveCollectiveProperties($inviteesList, $isCollective, $id);
291
                }
292
293
                if (api_get_configuration_value('agenda_event_subscriptions') && api_is_platform_admin()) {
294
                    $personalEvent = $em->find(PersonalAgenda::class, $id);
295
296
                    if ($personalEvent->hasInvitation()
297
                        && !($personalEvent->getInvitation() instanceof AgendaEventSubscription)
298
                    ) {
299
                        break;
300
                    }
301
302
                    $personalEvent
303
                        ->setSubscriptionVisibility($subscriptionVisibility)
304
                        ->setSubscriptionItemId($subscriptionItemId ?: null)
305
                    ;
306
307
                    $subscription = (new AgendaEventSubscription())
308
                        ->setCreator(api_get_user_entity(api_get_user_id()))
309
                        ->setMaxAttendees($subscriptionVisibility > 0 ? $maxSubscriptions : 0)
310
                    ;
311
312
                    $personalEvent
313
                        ->setCollective(false)
314
                        ->setInvitation($subscription)
315
                    ;
316
317
                    $em->flush();
318
                }
319
                break;
320
            case 'course':
321
                $attributes = [
322
                    'title' => $title,
323
                    'content' => Security::remove_XSS($content),
324
                    'start_date' => $start,
325
                    'end_date' => $end,
326
                    'all_day' => $allDay,
327
                    'session_id' => $this->getSessionId(),
328
                    'c_id' => $this->course['real_id'],
329
                    'comment' => $eventComment,
330
                    'color' => $color,
331
                ];
332
333
                if (!empty($parentEventId)) {
334
                    $attributes['parent_event_id'] = $parentEventId;
335
                }
336
                $this->deleteEventIfAlreadyExists($start, $end, $allDay, $title);
337
                $senderId = $this->getSenderId();
338
                $sessionId = $this->getSessionId();
339
340
                // Simple course event.
341
                $id = Database::insert($this->tbl_course_agenda, $attributes);
342
343
                if ($id) {
344
                    $sql = "UPDATE ".$this->tbl_course_agenda." SET id = iid WHERE iid = $id";
345
                    Database::query($sql);
346
347
                    $groupId = api_get_group_id();
348
                    $groupInfo = [];
349
                    if ($groupId) {
350
                        $groupInfo = GroupManager::get_group_properties(
351
                            $groupId
352
                        );
353
                    }
354
355
                    if (!empty($usersToSend)) {
356
                        $sendTo = $this->parseSendToArray($usersToSend);
357
                        if ($sendTo['everyone']) {
358
                            api_item_property_update(
359
                                $this->course,
360
                                TOOL_CALENDAR_EVENT,
361
                                $id,
362
                                'AgendaAdded',
363
                                $senderId,
364
                                $groupInfo,
365
                                '',
366
                                $start,
367
                                $end,
368
                                $sessionId
369
                            );
370
                            api_item_property_update(
371
                                $this->course,
372
                                TOOL_CALENDAR_EVENT,
373
                                $id,
374
                                'visible',
375
                                $senderId,
376
                                $groupInfo,
377
                                '',
378
                                $start,
379
                                $end,
380
                                $sessionId
381
                            );
382
                        } else {
383
                            // Storing the selected groups
384
                            if (!empty($sendTo['groups'])) {
385
                                foreach ($sendTo['groups'] as $group) {
386
                                    $groupInfoItem = [];
387
                                    if ($group) {
388
                                        $groupInfoItem = GroupManager::get_group_properties($group);
389
                                    }
390
391
                                    api_item_property_update(
392
                                        $this->course,
393
                                        TOOL_CALENDAR_EVENT,
394
                                        $id,
395
                                        'AgendaAdded',
396
                                        $senderId,
397
                                        $groupInfoItem,
398
                                        0,
399
                                        $start,
400
                                        $end,
401
                                        $sessionId
402
                                    );
403
404
                                    api_item_property_update(
405
                                        $this->course,
406
                                        TOOL_CALENDAR_EVENT,
407
                                        $id,
408
                                        'visible',
409
                                        $senderId,
410
                                        $groupInfoItem,
411
                                        0,
412
                                        $start,
413
                                        $end,
414
                                        $sessionId
415
                                    );
416
                                }
417
                            }
418
419
                            // storing the selected users
420
                            if (!empty($sendTo['users'])) {
421
                                foreach ($sendTo['users'] as $userId) {
422
                                    api_item_property_update(
423
                                        $this->course,
424
                                        TOOL_CALENDAR_EVENT,
425
                                        $id,
426
                                        'AgendaAdded',
427
                                        $senderId,
428
                                        $groupInfo,
429
                                        $userId,
430
                                        $start,
431
                                        $end,
432
                                        $sessionId
433
                                    );
434
435
                                    api_item_property_update(
436
                                        $this->course,
437
                                        TOOL_CALENDAR_EVENT,
438
                                        $id,
439
                                        'visible',
440
                                        $senderId,
441
                                        $groupInfo,
442
                                        $userId,
443
                                        $start,
444
                                        $end,
445
                                        $sessionId
446
                                    );
447
                                }
448
                            }
449
                        }
450
                    }
451
452
                    // Add announcement.
453
                    if ($addAsAnnouncement) {
454
                        $this->storeAgendaEventAsAnnouncement(
455
                            $id,
456
                            $usersToSend
457
                        );
458
                    }
459
460
                    // Add attachment.
461
                    if (isset($attachmentArray) && !empty($attachmentArray)) {
462
                        $counter = 0;
463
                        foreach ($attachmentArray as $attachmentItem) {
464
                            $this->addAttachment(
465
                                $id,
466
                                $attachmentItem,
467
                                $attachmentCommentList[$counter],
468
                                $this->course
469
                            );
470
                            $counter++;
471
                        }
472
                    }
473
                }
474
                break;
475
            case 'admin':
476
                if (api_is_platform_admin()) {
477
                    $attributes = [
478
                        'title' => $title,
479
                        'content' => Security::remove_XSS($content),
480
                        'start_date' => $start,
481
                        'end_date' => $end,
482
                        'all_day' => $allDay,
483
                        'access_url_id' => api_get_current_access_url_id(),
484
                    ];
485
486
                    if (api_get_configuration_value('allow_careers_in_global_agenda')) {
487
                        $attributes['career_id'] = $careerId;
488
                        $attributes['promotion_id'] = $promotionId;
489
                    }
490
491
                    $id = Database::insert(
492
                        $this->tbl_global_agenda,
493
                        $attributes
494
                    );
495
                }
496
                break;
497
        }
498
499
        if (api_get_configuration_value('agenda_reminders')) {
500
            foreach ($reminders as $reminder) {
501
                $this->addReminder($id, $reminder[0], $reminder[1]);
502
            }
503
        }
504
505
        return $id;
506
    }
507
508
    /**
509
     * Checks if an event exists and delete it (right before inserting a modified version in addEvent()).
510
     *
511
     * @param string $start  datetime format: 2012-06-14 09:00:00 in local time
512
     * @param string $end    datetime format: 2012-06-14 09:00:00 in local time
513
     * @param int    $allDay (true = 1, false = 0)
514
     *
515
     * @throws Exception
516
     */
517
    public function deleteEventIfAlreadyExists(
518
        string $start,
519
        string $end,
520
        int $allDay,
521
        string $title
522
    ): bool {
523
        $courseId = $this->course['real_id'];
524
        $start = Database::escape_string($start);
525
        $end = Database::escape_string($end);
526
        $title = Database::escape_string($title);
527
        $sql = "SELECT id FROM ".$this->tbl_course_agenda."
528
                WHERE c_id = $courseId
529
                AND session_id = ".$this->sessionId."
530
                AND start_date = '$start'
531
                AND end_date = '$end'
532
                AND all_day = $allDay
533
                AND title = '$title'";
534
        $res = Database::query($sql);
535
        if (Database::num_rows($res) > 0) {
536
            $row = Database::fetch_array($res, 'ASSOC');
537
            $id = $row['id'];
538
            $this->deleteEvent($id);
539
540
            return true;
541
        }
542
543
        return false;
544
    }
545
546
    /**
547
     * @throws Exception
548
     */
549
    public function addReminder($eventId, $count, $period)
550
    {
551
        switch ($period) {
552
            case 'i':
553
                $dateInterval = DateInterval::createFromDateString("$count minutes");
554
                break;
555
            case 'h':
556
                $dateInterval = DateInterval::createFromDateString("$count hours");
557
                break;
558
            case 'd':
559
                $dateInterval = DateInterval::createFromDateString("$count days");
560
                break;
561
            default:
562
                return null;
563
        }
564
565
        $agendaReminder = new AgendaReminder();
566
        $agendaReminder
567
            ->setType($this->type)
568
            ->setEventId($eventId)
569
            ->setDateInterval($dateInterval)
570
        ;
571
572
        $em = Database::getManager();
573
        $em->persist($agendaReminder);
574
        $em->flush();
575
    }
576
577
    public function removeReminders(int $eventId, int $count, string $period)
578
    {
579
        switch ($period) {
580
            case 'i':
581
                $dateInterval = DateInterval::createFromDateString("$count minutes");
582
                break;
583
            case 'h':
584
                $dateInterval = DateInterval::createFromDateString("$count hours");
585
                break;
586
            case 'd':
587
                $dateInterval = DateInterval::createFromDateString("$count days");
588
                break;
589
            default:
590
                return null;
591
        }
592
593
        Database::getManager()
594
            ->createQuery(
595
                'DELETE FROM ChamiloCoreBundle:AgendaReminder ar
596
                WHERE ar.eventId = :eventId AND ar.type = :type AND ar.dateInterval = :dateInterval'
597
            )
598
            ->setParameters(
599
                [
600
                    'eventId' => $eventId,
601
                    'type' => $this->type,
602
                    'dateInterval' => $dateInterval,
603
                ]
604
            )
605
            ->execute();
606
    }
607
608
    public function getReminder(int $eventId, int $count, string $period)
609
    {
610
        switch ($period) {
611
            case 'i':
612
                $dateInterval = DateInterval::createFromDateString("$count minutes");
613
                break;
614
            case 'h':
615
                $dateInterval = DateInterval::createFromDateString("$count hours");
616
                break;
617
            case 'd':
618
                $dateInterval = DateInterval::createFromDateString("$count days");
619
                break;
620
            default:
621
                return null;
622
        }
623
624
        $em = Database::getManager();
625
        $remindersRepo = $em->getRepository('ChamiloCoreBundle:AgendaReminder');
626
627
        return $remindersRepo->findOneBy(
628
            [
629
                'type' => $this->type,
630
                'dateInterval' => $dateInterval,
631
                'eventId' => $eventId,
632
            ]
633
        );
634
    }
635
636
    /**
637
     * @param int $eventId
638
     * @param int $courseId
639
     *
640
     * @return array
641
     */
642
    public function getRepeatedInfoByEvent($eventId, $courseId)
643
    {
644
        $repeatTable = Database::get_course_table(TABLE_AGENDA_REPEAT);
645
        $eventId = (int) $eventId;
646
        $courseId = (int) $courseId;
647
        $sql = "SELECT * FROM $repeatTable
648
                WHERE c_id = $courseId AND cal_id = $eventId";
649
        $res = Database::query($sql);
650
        $repeatInfo = [];
651
        if (Database::num_rows($res) > 0) {
652
            $repeatInfo = Database::fetch_array($res, 'ASSOC');
653
        }
654
655
        return $repeatInfo;
656
    }
657
658
    /**
659
     * @param string $type
660
     * @param string $startEvent      in UTC
661
     * @param string $endEvent        in UTC
662
     * @param string $repeatUntilDate in UTC
663
     *
664
     * @throws Exception
665
     *
666
     * @return array with local times
667
     */
668
    public function generateDatesByType($type, $startEvent, $endEvent, $repeatUntilDate)
669
    {
670
        $continue = true;
671
        $repeatUntilDate = new DateTime($repeatUntilDate, new DateTimeZone('UTC'));
672
        $loopMax = 365;
673
        $counter = 0;
674
        $list = [];
675
676
        switch ($type) {
677
            case 'daily':
678
                $interval = 'P1D';
679
                break;
680
            case 'weekly':
681
                $interval = 'P1W';
682
                break;
683
            case 'monthlyByDate':
684
                $interval = 'P1M';
685
                break;
686
            case 'monthlyByDay':
687
                // not yet implemented
688
                break;
689
            case 'monthlyByDayR':
690
                // not yet implemented
691
                break;
692
            case 'yearly':
693
                $interval = 'P1Y';
694
                break;
695
        }
696
697
        if (empty($interval)) {
698
            return [];
699
        }
700
        $timeZone = api_get_timezone();
701
702
        while ($continue) {
703
            $startDate = new DateTime($startEvent, new DateTimeZone('UTC'));
704
            $endDate = new DateTime($endEvent, new DateTimeZone('UTC'));
705
706
            $startDate->add(new DateInterval($interval));
707
            $endDate->add(new DateInterval($interval));
708
709
            $newStartDate = $startDate->format('Y-m-d H:i:s');
710
            $newEndDate = $endDate->format('Y-m-d H:i:s');
711
712
            $startEvent = $newStartDate;
713
            $endEvent = $newEndDate;
714
715
            if ($endDate > $repeatUntilDate) {
716
                break;
717
            }
718
719
            // @todo remove comment code
720
            // The code below was not adpating to saving light time but was doubling the difference with UTC time.
721
            // Might be necessary to adapt to update saving light time difference.
722
            /*            $startDateInLocal = new DateTime($newStartDate, new DateTimeZone($timeZone));
723
                        if ($startDateInLocal->format('I') == 0) {
724
                            // Is saving time? Then fix UTC time to add time
725
                            $seconds = $startDateInLocal->getOffset();
726
                            $startDate->add(new DateInterval("PT".$seconds."S"));
727
                            //$startDateFixed = $startDate->format('Y-m-d H:i:s');
728
                            //$startDateInLocalFixed = new DateTime($startDateFixed, new DateTimeZone($timeZone));
729
                            //$newStartDate = $startDateInLocalFixed->format('Y-m-d H:i:s');
730
                            //$newStartDate = $startDate->setTimezone(new DateTimeZone($timeZone))->format('Y-m-d H:i:s');
731
                        }
732
733
                        $endDateInLocal = new DateTime($newEndDate, new DateTimeZone($timeZone));
734
                        if ($endDateInLocal->format('I') == 0) {
735
                            // Is saving time? Then fix UTC time to add time
736
                            $seconds = $endDateInLocal->getOffset();
737
                            $endDate->add(new DateInterval("PT".$seconds."S"));
738
                            //$endDateFixed = $endDate->format('Y-m-d H:i:s');
739
                            //$endDateInLocalFixed = new DateTime($endDateFixed, new DateTimeZone($timeZone));
740
                            //$newEndDate = $endDateInLocalFixed->format('Y-m-d H:i:s');
741
                    }
742
            */
743
            $newStartDate = $startDate->setTimezone(new DateTimeZone($timeZone))->format('Y-m-d H:i:s');
744
            $newEndDate = $endDate->setTimezone(new DateTimeZone($timeZone))->format('Y-m-d H:i:s');
745
            $list[] = ['start' => $newStartDate, 'end' => $newEndDate];
746
            $counter++;
747
748
            // just in case stop if more than $loopMax
749
            if ($counter > $loopMax) {
750
                break;
751
            }
752
        }
753
754
        return $list;
755
    }
756
757
    /**
758
     * @param int    $eventId
759
     * @param string $type
760
     * @param string $end     in UTC
761
     * @param array  $sentTo
762
     *
763
     * @return bool
764
     */
765
    public function addRepeatedItem($eventId, $type, $end, $sentTo = [])
766
    {
767
        $t_agenda = Database::get_course_table(TABLE_AGENDA);
768
        $t_agenda_r = Database::get_course_table(TABLE_AGENDA_REPEAT);
769
770
        if (empty($this->course)) {
771
            return false;
772
        }
773
774
        $courseId = $this->course['real_id'];
775
        $eventId = (int) $eventId;
776
777
        $sql = "SELECT title, content, start_date, end_date, all_day
778
                FROM $t_agenda
779
                WHERE c_id = $courseId AND id = $eventId";
780
        $res = Database::query($sql);
781
782
        if (Database::num_rows($res) !== 1) {
783
            return false;
784
        }
785
786
        $typeList = [
787
            'daily',
788
            'weekly',
789
            'monthlyByDate',
790
            'monthlyByDay',
791
            'monthlyByDayR',
792
            'yearly',
793
        ];
794
795
        if (!in_array($type, $typeList)) {
796
            return false;
797
        }
798
799
        $now = time();
800
801
        // The event has to repeat *in the future*. We don't allow repeated
802
        // events in the past.
803
        $endTimeStamp = api_strtotime($end, 'UTC');
804
805
        if ($endTimeStamp < $now) {
806
            return false;
807
        }
808
809
        $row = Database::fetch_array($res);
810
811
        $title = $row['title'];
812
        $content = $row['content'];
813
        $allDay = $row['all_day'];
814
815
        $type = Database::escape_string($type);
816
        $end = Database::escape_string($end);
817
818
        $sql = "INSERT INTO $t_agenda_r (c_id, cal_id, cal_type, cal_end)
819
                VALUES ($courseId, '$eventId', '$type', '$endTimeStamp')";
820
        Database::query($sql);
821
822
        $generatedDates = $this->generateDatesByType($type, $row['start_date'], $row['end_date'], $end);
823
824
        if (empty($generatedDates)) {
825
            return false;
826
        }
827
828
        foreach ($generatedDates as $dateInfo) {
829
//            $start = api_get_local_time($dateInfo['start']);
830
//            $end = api_get_local_time($dateInfo['end']);
831
            // On line 529 in function generateDatesByType there is a @todo remove comment code
832
            // just before the part updating the date in local time so keep both synchronised
833
            $start = $dateInfo['start'];
834
            $end = $dateInfo['end'];
835
836
            $this->addEvent(
837
                $start,
838
                $end,
839
                $allDay,
840
                $title,
841
                $content,
842
                $sentTo,
843
                false,
844
                $eventId
845
            );
846
        }
847
848
        return true;
849
    }
850
851
    /**
852
     * @param int   $item_id
853
     * @param array $sentTo
854
     *
855
     * @return int
856
     */
857
    public function storeAgendaEventAsAnnouncement($item_id, $sentTo = [])
858
    {
859
        $table_agenda = Database::get_course_table(TABLE_AGENDA);
860
        $courseId = api_get_course_int_id();
861
862
        // Check params
863
        if (empty($item_id) || $item_id != strval(intval($item_id))) {
864
            return -1;
865
        }
866
867
        // Get the agenda item.
868
        $item_id = intval($item_id);
869
        $sql = "SELECT * FROM $table_agenda
870
                WHERE c_id = $courseId AND id = ".$item_id;
871
        $res = Database::query($sql);
872
873
        if (Database::num_rows($res) > 0) {
874
            $row = Database::fetch_array($res, 'ASSOC');
875
876
            // Sending announcement
877
            if (!empty($sentTo)) {
878
                $id = AnnouncementManager::add_announcement(
879
                    api_get_course_info(),
880
                    api_get_session_id(),
881
                    $row['title'],
882
                    $row['content'],
883
                    $sentTo,
884
                    null,
885
                    null,
886
                    $row['end_date']
887
                );
888
889
                AnnouncementManager::sendEmail(
890
                    api_get_course_info(),
891
                    api_get_session_id(),
892
                    $id
893
                );
894
895
                return $id;
896
            }
897
        }
898
899
        return -1;
900
    }
901
902
    /**
903
     * Edits an event.
904
     *
905
     * @param int    $id
906
     * @param string $start                 datetime format: 2012-06-14 09:00:00
907
     * @param string $end                   datetime format: 2012-06-14 09:00:00
908
     * @param int    $allDay                is all day 'true' or 'false'
909
     * @param string $title
910
     * @param string $content
911
     * @param array  $usersToSend
912
     * @param array  $attachmentArray
913
     * @param array  $attachmentCommentList
914
     * @param string $comment
915
     * @param string $color
916
     * @param bool   $addAnnouncement
917
     * @param bool   $updateContent
918
     * @param int    $authorId
919
     *
920
     * @return bool
921
     */
922
    public function editEvent(
923
        $id,
924
        $start,
925
        $end,
926
        $allDay,
927
        $title,
928
        $content,
929
        $usersToSend = [],
930
        $attachmentArray = [],
931
        $attachmentCommentList = [],
932
        $comment = null,
933
        $color = '',
934
        $addAnnouncement = false,
935
        $updateContent = true,
936
        $authorId = 0,
937
        array $inviteesList = [],
938
        bool $isCollective = false,
939
        array $remindersList = [],
940
        int $careerId = 0,
941
        int $promotionId = 0,
942
        int $subscriptionVisibility = 0,
943
        ?int $subscriptionItemId = null,
944
        int $maxSubscriptions = 0,
945
        array $subscribers = []
946
    ) {
947
        $id = (int) $id;
948
        $start = api_get_utc_datetime($start);
949
        $end = api_get_utc_datetime($end);
950
        $allDay = isset($allDay) && $allDay == 'true' ? 1 : 0;
951
        $currentUserId = api_get_user_id();
952
        $authorId = empty($authorId) ? $currentUserId : (int) $authorId;
953
954
        $em = Database::getManager();
955
956
        switch ($this->type) {
957
            case 'personal':
958
                $eventInfo = $this->get_event($id);
959
                if ($eventInfo['user'] != $currentUserId
960
                    && (
961
                        api_get_configuration_value('agenda_collective_invitations')
962
                            && !self::isUserInvitedInEvent($id, $currentUserId)
963
                    )
964
                ) {
965
                    break;
966
                }
967
                $attributes = [
968
                    'title' => $title,
969
                    'date' => $start,
970
                    'enddate' => $end,
971
                    'all_day' => $allDay,
972
                ];
973
974
                if ($updateContent) {
975
                    $attributes['text'] = $content;
976
                }
977
978
                if (!empty($color)) {
979
                    $attributes['color'] = $color;
980
                }
981
982
                Database::update(
983
                    $this->tbl_personal_agenda,
984
                    $attributes,
985
                    ['id = ?' => $id]
986
                );
987
988
                if (api_get_configuration_value('agenda_collective_invitations')) {
989
                    Agenda::saveCollectiveProperties($inviteesList, $isCollective, $id);
990
                }
991
992
                if (api_get_configuration_value('agenda_event_subscriptions') && api_is_platform_admin()) {
993
                    $personalEvent = $em->find(PersonalAgenda::class, $id);
994
995
                    if ($personalEvent->hasInvitation()
996
                        && !($personalEvent->getInvitation() instanceof AgendaEventSubscription)
997
                    ) {
998
                        break;
999
                    }
1000
1001
                    $personalEvent->setSubscriptionVisibility($subscriptionVisibility);
1002
1003
                    /** @var AgendaEventSubscription $subscription */
1004
                    $subscription = $personalEvent->getInvitation();
1005
1006
                    if ($subscription) {
1007
                        $subscription->setMaxAttendees($subscriptionVisibility > 0 ? $maxSubscriptions : 0);
1008
1009
                        if ($personalEvent->getSubscriptionItemId() != $subscriptionItemId) {
1010
                            $personalEvent->setSubscriptionItemId($subscriptionItemId ?: null);
1011
                            $subscription->removeInvitees();
1012
                        } else {
1013
                            $subscription->removeInviteesNotInIdList($subscribers);
1014
                        }
1015
1016
                        $em->flush();
1017
                    }
1018
                }
1019
                break;
1020
            case 'course':
1021
                $eventInfo = $this->get_event($id);
1022
1023
                if (empty($eventInfo)) {
1024
                    return false;
1025
                }
1026
1027
                $groupId = api_get_group_id();
1028
                $groupIid = 0;
1029
                $groupInfo = [];
1030
                if ($groupId) {
1031
                    $groupInfo = GroupManager::get_group_properties($groupId);
1032
                    if ($groupInfo) {
1033
                        $groupIid = $groupInfo['iid'];
1034
                    }
1035
                }
1036
1037
                $courseId = $this->course['real_id'];
1038
1039
                if (empty($courseId)) {
1040
                    return false;
1041
                }
1042
1043
                if (!$this->getIsAllowedToEdit()) {
1044
                    return false;
1045
                }
1046
1047
                $attributes = [
1048
                    'title' => $title,
1049
                    'start_date' => $start,
1050
                    'end_date' => $end,
1051
                    'all_day' => $allDay,
1052
                    'comment' => $comment,
1053
                ];
1054
1055
                if ($updateContent) {
1056
                    $attributes['content'] = $content;
1057
                }
1058
1059
                if (!empty($color)) {
1060
                    $attributes['color'] = $color;
1061
                }
1062
1063
                Database::update(
1064
                    $this->tbl_course_agenda,
1065
                    $attributes,
1066
                    [
1067
                        'id = ? AND c_id = ? AND session_id = ? ' => [
1068
                            $id,
1069
                            $courseId,
1070
                            $this->sessionId,
1071
                        ],
1072
                    ]
1073
                );
1074
1075
                if (!empty($usersToSend)) {
1076
                    $sendTo = $this->parseSendToArray($usersToSend);
1077
1078
                    $usersToDelete = array_diff(
1079
                        $eventInfo['send_to']['users'],
1080
                        $sendTo['users']
1081
                    );
1082
                    $usersToAdd = array_diff(
1083
                        $sendTo['users'],
1084
                        $eventInfo['send_to']['users']
1085
                    );
1086
1087
                    $groupsToDelete = array_diff(
1088
                        $eventInfo['send_to']['groups'],
1089
                        $sendTo['groups']
1090
                    );
1091
                    $groupToAdd = array_diff(
1092
                        $sendTo['groups'],
1093
                        $eventInfo['send_to']['groups']
1094
                    );
1095
1096
                    if ($sendTo['everyone']) {
1097
                        // Delete all from group
1098
                        if (isset($eventInfo['send_to']['groups']) &&
1099
                            !empty($eventInfo['send_to']['groups'])
1100
                        ) {
1101
                            foreach ($eventInfo['send_to']['groups'] as $group) {
1102
                                $groupIidItem = 0;
1103
                                if ($group) {
1104
                                    $groupInfoItem = GroupManager::get_group_properties(
1105
                                        $group
1106
                                    );
1107
                                    if ($groupInfoItem) {
1108
                                        $groupIidItem = $groupInfoItem['iid'];
1109
                                    }
1110
                                }
1111
1112
                                api_item_property_delete(
1113
                                    $this->course,
1114
                                    TOOL_CALENDAR_EVENT,
1115
                                    $id,
1116
                                    0,
1117
                                    $groupIidItem,
1118
                                    $this->sessionId
1119
                                );
1120
                            }
1121
                        }
1122
1123
                        // Storing the selected users.
1124
                        if (isset($eventInfo['send_to']['users']) &&
1125
                            !empty($eventInfo['send_to']['users'])
1126
                        ) {
1127
                            foreach ($eventInfo['send_to']['users'] as $userId) {
1128
                                api_item_property_delete(
1129
                                    $this->course,
1130
                                    TOOL_CALENDAR_EVENT,
1131
                                    $id,
1132
                                    $userId,
1133
                                    $groupIid,
1134
                                    $this->sessionId
1135
                                );
1136
                            }
1137
                        }
1138
1139
                        // Add to everyone only.
1140
                        api_item_property_update(
1141
                            $this->course,
1142
                            TOOL_CALENDAR_EVENT,
1143
                            $id,
1144
                            'visible',
1145
                            $authorId,
1146
                            $groupInfo,
1147
                            null,
1148
                            $start,
1149
                            $end,
1150
                            $this->sessionId
1151
                        );
1152
                    } else {
1153
                        // Delete "everyone".
1154
                        api_item_property_delete(
1155
                            $this->course,
1156
                            TOOL_CALENDAR_EVENT,
1157
                            $id,
1158
                            0,
1159
                            0,
1160
                            $this->sessionId
1161
                        );
1162
1163
                        // Add groups
1164
                        if (!empty($groupToAdd)) {
1165
                            foreach ($groupToAdd as $group) {
1166
                                $groupInfoItem = [];
1167
                                if ($group) {
1168
                                    $groupInfoItem = GroupManager::get_group_properties(
1169
                                        $group
1170
                                    );
1171
                                }
1172
1173
                                api_item_property_update(
1174
                                    $this->course,
1175
                                    TOOL_CALENDAR_EVENT,
1176
                                    $id,
1177
                                    'visible',
1178
                                    $authorId,
1179
                                    $groupInfoItem,
1180
                                    0,
1181
                                    $start,
1182
                                    $end,
1183
                                    $this->sessionId
1184
                                );
1185
                            }
1186
                        }
1187
1188
                        // Delete groups.
1189
                        if (!empty($groupsToDelete)) {
1190
                            foreach ($groupsToDelete as $group) {
1191
                                $groupIidItem = 0;
1192
                                $groupInfoItem = [];
1193
                                if ($group) {
1194
                                    $groupInfoItem = GroupManager::get_group_properties(
1195
                                        $group
1196
                                    );
1197
                                    if ($groupInfoItem) {
1198
                                        $groupIidItem = $groupInfoItem['iid'];
1199
                                    }
1200
                                }
1201
1202
                                api_item_property_delete(
1203
                                    $this->course,
1204
                                    TOOL_CALENDAR_EVENT,
1205
                                    $id,
1206
                                    0,
1207
                                    $groupIidItem,
1208
                                    $this->sessionId
1209
                                );
1210
                            }
1211
                        }
1212
1213
                        // Add users.
1214
                        if (!empty($usersToAdd)) {
1215
                            foreach ($usersToAdd as $userId) {
1216
                                api_item_property_update(
1217
                                    $this->course,
1218
                                    TOOL_CALENDAR_EVENT,
1219
                                    $id,
1220
                                    'visible',
1221
                                    $authorId,
1222
                                    $groupInfo,
1223
                                    $userId,
1224
                                    $start,
1225
                                    $end,
1226
                                    $this->sessionId
1227
                                );
1228
                            }
1229
                        }
1230
1231
                        // Delete users.
1232
                        if (!empty($usersToDelete)) {
1233
                            foreach ($usersToDelete as $userId) {
1234
                                api_item_property_delete(
1235
                                    $this->course,
1236
                                    TOOL_CALENDAR_EVENT,
1237
                                    $id,
1238
                                    $userId,
1239
                                    $groupInfo,
1240
                                    $this->sessionId
1241
                                );
1242
                            }
1243
                        }
1244
                    }
1245
                }
1246
1247
                // Add announcement.
1248
                if (isset($addAnnouncement) && !empty($addAnnouncement)) {
1249
                    $this->storeAgendaEventAsAnnouncement(
1250
                        $id,
1251
                        $usersToSend
1252
                    );
1253
                }
1254
1255
                // Add attachment.
1256
                if (isset($attachmentArray) && !empty($attachmentArray)) {
1257
                    $counter = 0;
1258
                    foreach ($attachmentArray as $attachmentItem) {
1259
                        if (empty($attachmentItem['id'])) {
1260
                            $this->addAttachment(
1261
                                $id,
1262
                                $attachmentItem,
1263
                                $attachmentCommentList[$counter],
1264
                                $this->course
1265
                            );
1266
                        } else {
1267
                            $this->updateAttachment(
1268
                                $attachmentItem['id'],
1269
                                $id,
1270
                                $attachmentItem,
1271
                                $attachmentCommentList[$counter],
1272
                                $this->course
1273
                            );
1274
                        }
1275
                        $counter++;
1276
                    }
1277
                }
1278
                break;
1279
            case 'admin':
1280
            case 'platform':
1281
                if (api_is_platform_admin()) {
1282
                    $attributes = [
1283
                        'title' => $title,
1284
                        'start_date' => $start,
1285
                        'end_date' => $end,
1286
                        'all_day' => $allDay,
1287
                    ];
1288
1289
                    if (api_get_configuration_value('allow_careers_in_global_agenda')) {
1290
                        $attributes['career_id'] = $careerId;
1291
                        $attributes['promotion_id'] = $promotionId;
1292
                    }
1293
1294
                    if ($updateContent) {
1295
                        $attributes['content'] = $content;
1296
                    }
1297
                    Database::update(
1298
                        $this->tbl_global_agenda,
1299
                        $attributes,
1300
                        ['id = ?' => $id]
1301
                    );
1302
                }
1303
                break;
1304
        }
1305
1306
        $this->editReminders($id, $remindersList);
1307
1308
        return true;
1309
    }
1310
1311
    /**
1312
     * @param int  $id
1313
     * @param bool $deleteAllItemsFromSerie
1314
     *
1315
     * @throws \Doctrine\ORM\ORMException
1316
     * @throws \Doctrine\ORM\OptimisticLockException
1317
     */
1318
    public function deleteEvent($id, $deleteAllItemsFromSerie = false)
1319
    {
1320
        $em = Database::getManager();
1321
1322
        switch ($this->type) {
1323
            case 'personal':
1324
                $eventInfo = $this->get_event($id);
1325
                if ($eventInfo['user'] == api_get_user_id()) {
1326
                    Database::delete(
1327
                        $this->tbl_personal_agenda,
1328
                        ['id = ?' => $id]
1329
                    );
1330
                } elseif (api_get_configuration_value('agenda_collective_invitations')) {
1331
                    $currentUser = api_get_user_entity(api_get_user_id());
1332
1333
                    $eventRepo = $em->getRepository('ChamiloCoreBundle:PersonalAgenda');
1334
                    $event = $eventRepo->findOneByIdAndInvitee($id, $currentUser);
1335
                    $invitation = $event ? $event->getInvitation() : null;
1336
1337
                    if ($invitation) {
1338
                        $invitation->removeInviteeUser($currentUser);
1339
1340
                        $em->persist($invitation);
1341
                        $em->flush();
1342
                    }
1343
                }
1344
                break;
1345
            case 'course':
1346
                $courseId = api_get_course_int_id();
1347
                $isAllowToEdit = $this->getIsAllowedToEdit();
1348
1349
                if (!empty($courseId) && $isAllowToEdit) {
1350
                    $eventInfo = $this->get_event($id);
1351
                    if ($deleteAllItemsFromSerie) {
1352
                        /* This is one of the children.
1353
                           Getting siblings and delete 'Em all + the father! */
1354
                        if (isset($eventInfo['parent_event_id']) && !empty($eventInfo['parent_event_id'])) {
1355
                            // Removing items.
1356
                            $events = $this->getAllRepeatEvents($eventInfo['parent_event_id']);
1357
                            if (!empty($events)) {
1358
                                foreach ($events as $event) {
1359
                                    $this->deleteEvent($event['id']);
1360
                                }
1361
                            }
1362
                            // Removing parent.
1363
                            $this->deleteEvent($eventInfo['parent_event_id']);
1364
                        } else {
1365
                            // This is the father looking for the children.
1366
                            $events = $this->getAllRepeatEvents($id);
1367
                            if (!empty($events)) {
1368
                                foreach ($events as $event) {
1369
                                    $this->deleteEvent($event['id']);
1370
                                }
1371
                            }
1372
                        }
1373
                    }
1374
1375
                    // Removing from events.
1376
                    Database::delete(
1377
                        $this->tbl_course_agenda,
1378
                        ['id = ? AND c_id = ?' => [$id, $courseId]]
1379
                    );
1380
1381
                    api_item_property_update(
1382
                        $this->course,
1383
                        TOOL_CALENDAR_EVENT,
1384
                        $id,
1385
                        'delete',
1386
                        api_get_user_id()
1387
                    );
1388
1389
                    // Removing from series.
1390
                    Database::delete(
1391
                        $this->table_repeat,
1392
                        [
1393
                            'cal_id = ? AND c_id = ?' => [
1394
                                $id,
1395
                                $courseId,
1396
                            ],
1397
                        ]
1398
                    );
1399
1400
                    if (isset($eventInfo['attachment']) && !empty($eventInfo['attachment'])) {
1401
                        foreach ($eventInfo['attachment'] as $attachment) {
1402
                            self::deleteAttachmentFile(
1403
                                $attachment['id'],
1404
                                $this->course
1405
                            );
1406
                        }
1407
                    }
1408
                }
1409
                break;
1410
            case 'admin':
1411
                if (api_is_platform_admin()) {
1412
                    Database::delete(
1413
                        $this->tbl_global_agenda,
1414
                        ['id = ?' => $id]
1415
                    );
1416
                }
1417
                break;
1418
        }
1419
    }
1420
1421
    public function exportEventMembersToCsv(int $id, $type = "Invitee")
1422
    {
1423
        if (false === api_get_configuration_value('agenda_event_subscriptions') && false === api_get_configuration_value('agenda_collective_invitations')) {
1424
            return;
1425
        }
1426
        if ('personal' !== $this->type) {
1427
            return;
1428
        }
1429
        if ($type === "Invitee") {
1430
            $members = self::getInviteesForPersonalEvent($id, AgendaEventInvitee::class);
1431
        } elseif ($type === "Subscriber") {
1432
            $members = self::getInviteesForPersonalEvent($id, AgendaEventSubscriber::class);
1433
        }
1434
        $data = [];
1435
        $data[] = [
1436
            'OfficialCode',
1437
            'Lastname',
1438
            'Firsname',
1439
            'Email',
1440
        ];
1441
        $count = 1;
1442
        foreach ($members as $member) {
1443
            $user = api_get_user_info($member['id']);
1444
            $data[$count][] = $user['official_code'];
1445
            $data[$count][] = $user['lastname'];
1446
            $data[$count][] = $user['firstname'];
1447
            $data[$count][] = $user['email'];
1448
            $count++;
1449
        }
1450
1451
        return $data;
1452
    }
1453
1454
    public function subscribeCurrentUserToEvent(int $id)
1455
    {
1456
        if (false === api_get_configuration_value('agenda_event_subscriptions')) {
1457
            return;
1458
        }
1459
1460
        if ('personal' !== $this->type) {
1461
            return;
1462
        }
1463
1464
        $em = Database::getManager();
1465
1466
        $currentUser = api_get_user_entity(api_get_user_id());
1467
        $personalEvent = $em->find(PersonalAgenda::class, $id);
1468
1469
        /** @var AgendaEventSubscription $subscription */
1470
        $subscription = $personalEvent ? $personalEvent->getInvitation() : null;
1471
1472
        if (!$subscription) {
1473
            return;
1474
        }
1475
1476
        if ($subscription->getInvitees()->count() >= $subscription->getMaxAttendees()
1477
            && $subscription->getMaxAttendees() > 0
1478
        ) {
1479
            return;
1480
        }
1481
1482
        if (AgendaEventSubscription::SUBSCRIPTION_CLASS === $personalEvent->getSubscriptionVisibility()) {
1483
            $objGroup = new UserGroup();
1484
            $groupList = $objGroup->getUserGroupListByUser($currentUser->getId(), UserGroup::NORMAL_CLASS);
1485
            $groupIdList = array_column($groupList, 'id');
1486
1487
            if (!in_array($personalEvent->getSubscriptionItemId(), $groupIdList)) {
1488
                return;
1489
            }
1490
        }
1491
1492
        $subscriber = (new AgendaEventSubscriber())
1493
            ->setUser($currentUser)
1494
        ;
1495
1496
        $subscription->addInvitee($subscriber);
1497
1498
        $em->flush();
1499
    }
1500
1501
    public function unsubscribeCurrentUserToEvent(int $id)
1502
    {
1503
        if (false === api_get_configuration_value('agenda_event_subscriptions')) {
1504
            return;
1505
        }
1506
1507
        if ('personal' !== $this->type) {
1508
            return;
1509
        }
1510
1511
        $em = Database::getManager();
1512
1513
        $currentUser = api_get_user_entity(api_get_user_id());
1514
        $personalEvent = $em->find(PersonalAgenda::class, $id);
1515
1516
        /** @var AgendaEventSubscription $subscription */
1517
        $subscription = $personalEvent ? $personalEvent->getInvitation() : null;
1518
1519
        if (!$subscription) {
1520
            return;
1521
        }
1522
1523
        $subscription->removeInviteeUser($currentUser);
1524
1525
        $em->flush();
1526
    }
1527
1528
    /**
1529
     * Get agenda events.
1530
     *
1531
     * @param int    $start
1532
     * @param int    $end
1533
     * @param int    $courseId
1534
     * @param int    $groupId
1535
     * @param int    $user_id
1536
     * @param string $format
1537
     *
1538
     * @return array|string
1539
     */
1540
    public function getEvents(
1541
        $start,
1542
        $end,
1543
        $courseId = null,
1544
        $groupId = null,
1545
        $user_id = 0,
1546
        $format = 'json'
1547
    ) {
1548
        switch ($this->type) {
1549
            case 'admin':
1550
                $this->getPlatformEvents($start, $end);
1551
                break;
1552
            case 'course':
1553
                $courseInfo = api_get_course_info_by_id($courseId);
1554
1555
                // Session coach can see all events inside a session.
1556
                if (api_is_coach()) {
1557
                    // Own course
1558
                    $this->getCourseEvents(
1559
                        $start,
1560
                        $end,
1561
                        $courseInfo,
1562
                        $groupId,
1563
                        $this->sessionId,
1564
                        $user_id
1565
                    );
1566
1567
                    // Others
1568
                    $this->getSessionEvents(
1569
                        $start,
1570
                        $end,
1571
                        $this->sessionId,
1572
                        $user_id,
1573
                        $this->eventOtherSessionColor
1574
                    );
1575
                } else {
1576
                    $this->getCourseEvents(
1577
                        $start,
1578
                        $end,
1579
                        $courseInfo,
1580
                        $groupId,
1581
                        $this->sessionId,
1582
                        $user_id
1583
                    );
1584
                }
1585
                break;
1586
            case 'personal':
1587
            default:
1588
                $sessionFilterActive = false;
1589
                if (!empty($this->sessionId)) {
1590
                    $sessionFilterActive = true;
1591
                }
1592
1593
                if ($sessionFilterActive == false) {
1594
                    // Getting personal events
1595
                    $this->getPersonalEvents($start, $end);
1596
1597
                    // Getting platform/admin events
1598
                    $this->getPlatformEvents($start, $end);
1599
                }
1600
1601
                $ignoreVisibility = api_get_configuration_value('personal_agenda_show_all_session_events');
1602
1603
                $session_list = [];
1604
                // Getting course events
1605
                $my_course_list = [];
1606
                if (!api_is_anonymous()) {
1607
                    $session_list = SessionManager::get_sessions_by_user(
1608
                        api_get_user_id(),
1609
                        $ignoreVisibility
1610
                    );
1611
                    $my_course_list = CourseManager::get_courses_list_by_user_id(
1612
                        api_get_user_id(),
1613
                        false
1614
                    );
1615
                }
1616
1617
                if (api_is_drh()) {
1618
                    if (api_drh_can_access_all_session_content()) {
1619
                        $session_list = [];
1620
                        $sessionList = SessionManager::get_sessions_followed_by_drh(
1621
                            api_get_user_id(),
1622
                            null,
1623
                            null,
1624
                            null,
1625
                            true,
1626
                            false
1627
                        );
1628
1629
                        if (!empty($sessionList)) {
1630
                            foreach ($sessionList as $sessionItem) {
1631
                                $sessionId = $sessionItem['id'];
1632
                                $courses = SessionManager::get_course_list_by_session_id($sessionId);
1633
                                $sessionInfo = [
1634
                                    'session_id' => $sessionId,
1635
                                    'courses' => $courses,
1636
                                ];
1637
                                $session_list[] = $sessionInfo;
1638
                            }
1639
                        }
1640
                    }
1641
                }
1642
1643
                if (!empty($session_list)) {
1644
                    foreach ($session_list as $session_item) {
1645
                        if ($sessionFilterActive) {
1646
                            if ($this->sessionId != $session_item['session_id']) {
1647
                                continue;
1648
                            }
1649
                        }
1650
1651
                        $my_courses = $session_item['courses'];
1652
                        $my_session_id = $session_item['session_id'];
1653
1654
                        if (!empty($my_courses)) {
1655
                            foreach ($my_courses as $course_item) {
1656
                                $courseInfo = api_get_course_info_by_id(
1657
                                    $course_item['real_id']
1658
                                );
1659
                                $this->getCourseEvents(
1660
                                    $start,
1661
                                    $end,
1662
                                    $courseInfo,
1663
                                    0,
1664
                                    $my_session_id
1665
                                );
1666
                            }
1667
                        }
1668
                    }
1669
                }
1670
1671
                if (!empty($my_course_list) && $sessionFilterActive == false) {
1672
                    foreach ($my_course_list as $courseInfoItem) {
1673
                        $courseInfo = api_get_course_info_by_id(
1674
                            $courseInfoItem['real_id']
1675
                        );
1676
                        if (isset($courseId) && !empty($courseId)) {
1677
                            if ($courseInfo['real_id'] == $courseId) {
1678
                                $this->getCourseEvents(
1679
                                    $start,
1680
                                    $end,
1681
                                    $courseInfo,
1682
                                    0,
1683
                                    0,
1684
                                    $user_id
1685
                                );
1686
                            }
1687
                        } else {
1688
                            $this->getCourseEvents(
1689
                                $start,
1690
                                $end,
1691
                                $courseInfo,
1692
                                0,
1693
                                0,
1694
                                $user_id
1695
                            );
1696
                        }
1697
                    }
1698
                }
1699
1700
                if ($start && $end) {
1701
                    $this->loadSessionsAsEvents($start, $end);
1702
                }
1703
1704
                break;
1705
        }
1706
1707
        if (api_get_configuration_value('agenda_reminders')) {
1708
            $this->events = array_map(
1709
                function (array $eventInfo) {
1710
                    $id = str_replace(['personal_', 'course_', 'session_'], '', $eventInfo['id']);
1711
1712
                    $eventInfo['reminders'] = $this->parseEventReminders(
1713
                        $this->getEventReminders(
1714
                            $id,
1715
                            'session' === $eventInfo['type'] ? 'course' : $eventInfo['type']
1716
                        )
1717
                    );
1718
1719
                    return $eventInfo;
1720
                },
1721
                $this->events
1722
            );
1723
        }
1724
1725
        $this->cleanEvents();
1726
1727
        switch ($format) {
1728
            case 'json':
1729
                if (empty($this->events)) {
1730
                    return '[]';
1731
                }
1732
1733
                return json_encode($this->events);
1734
                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...
1735
            case 'array':
1736
                if (empty($this->events)) {
1737
                    return [];
1738
                }
1739
1740
                return $this->events;
1741
                break;
1742
        }
1743
    }
1744
1745
    /**
1746
     * Clean events.
1747
     *
1748
     * @return bool
1749
     */
1750
    public function cleanEvents()
1751
    {
1752
        if (empty($this->events)) {
1753
            return false;
1754
        }
1755
1756
        foreach ($this->events as &$event) {
1757
            $event['description'] = Security::remove_XSS($event['description']);
1758
            $event['title'] = Security::remove_XSS($event['title']);
1759
        }
1760
1761
        return true;
1762
    }
1763
1764
    /**
1765
     * @param int $id
1766
     * @param int $minute_delta
1767
     *
1768
     * @return int
1769
     */
1770
    public function resizeEvent($id, $minute_delta)
1771
    {
1772
        $id = (int) $id;
1773
        $delta = (int) $minute_delta;
1774
        $event = $this->get_event($id);
1775
        if (!empty($event)) {
1776
            switch ($this->type) {
1777
                case 'personal':
1778
                    $sql = "UPDATE $this->tbl_personal_agenda SET
1779
                            enddate = DATE_ADD(enddate, INTERVAL $delta MINUTE)
1780
							WHERE id = ".$id;
1781
                    Database::query($sql);
1782
                    break;
1783
                case 'course':
1784
                    $sql = "UPDATE $this->tbl_course_agenda SET
1785
                            end_date = DATE_ADD(end_date, INTERVAL $delta MINUTE)
1786
							WHERE
1787
							    c_id = ".$this->course['real_id']." AND
1788
							    id = ".$id;
1789
                    Database::query($sql);
1790
                    break;
1791
                case 'admin':
1792
                    $sql = "UPDATE $this->tbl_global_agenda SET
1793
                            end_date = DATE_ADD(end_date, INTERVAL $delta MINUTE)
1794
							WHERE id = ".$id;
1795
                    Database::query($sql);
1796
                    break;
1797
            }
1798
        }
1799
1800
        return 1;
1801
    }
1802
1803
    /**
1804
     * @param int $id
1805
     * @param int $minute_delta minutes
1806
     * @param int $allDay
1807
     *
1808
     * @return int
1809
     */
1810
    public function move_event($id, $minute_delta, $allDay)
1811
    {
1812
        $id = (int) $id;
1813
        $event = $this->get_event($id);
1814
1815
        if (empty($event)) {
1816
            return false;
1817
        }
1818
1819
        // we convert the hour delta into minutes and add the minute delta
1820
        $delta = (int) $minute_delta;
1821
        $allDay = (int) $allDay;
1822
1823
        if (!empty($event)) {
1824
            switch ($this->type) {
1825
                case 'personal':
1826
                    $sql = "UPDATE $this->tbl_personal_agenda SET
1827
                            all_day = $allDay, date = DATE_ADD(date, INTERVAL $delta MINUTE),
1828
                            enddate = DATE_ADD(enddate, INTERVAL $delta MINUTE)
1829
							WHERE id=".$id;
1830
                    Database::query($sql);
1831
                    break;
1832
                case 'course':
1833
                    $sql = "UPDATE $this->tbl_course_agenda SET
1834
                            all_day = $allDay,
1835
                            start_date = DATE_ADD(start_date, INTERVAL $delta MINUTE),
1836
                            end_date = DATE_ADD(end_date, INTERVAL $delta MINUTE)
1837
							WHERE
1838
							    c_id = ".$this->course['real_id']." AND
1839
							    id=".$id;
1840
                    Database::query($sql);
1841
                    break;
1842
                case 'admin':
1843
                    $sql = "UPDATE $this->tbl_global_agenda SET
1844
                            all_day = $allDay,
1845
                            start_date = DATE_ADD(start_date,INTERVAL $delta MINUTE),
1846
                            end_date = DATE_ADD(end_date, INTERVAL $delta MINUTE)
1847
							WHERE id=".$id;
1848
                    Database::query($sql);
1849
                    break;
1850
            }
1851
        }
1852
1853
        return 1;
1854
    }
1855
1856
    /**
1857
     * Gets a single event.
1858
     *
1859
     * @param int $id event id
1860
     *
1861
     * @return array
1862
     */
1863
    public function get_event($id)
1864
    {
1865
        // make sure events of the personal agenda can only be seen by the user himself
1866
        $id = (int) $id;
1867
        $event = null;
1868
        $agendaCollectiveInvitations = api_get_configuration_value('agenda_collective_invitations');
1869
1870
        switch ($this->type) {
1871
            case 'personal':
1872
                $user = api_get_user_entity(api_get_user_id());
1873
                $sql = "SELECT * FROM ".$this->tbl_personal_agenda."
1874
                        WHERE id = $id AND user = ".$user->getId();
1875
                $result = Database::query($sql);
1876
                if (Database::num_rows($result)) {
1877
                    $event = Database::fetch_array($result, 'ASSOC');
1878
                    $event['description'] = $event['text'];
1879
                    $event['content'] = Security::remove_XSS($event['text'], STUDENT);
1880
                    $event['start_date'] = $event['date'];
1881
                    $event['end_date'] = $event['enddate'];
1882
                }
1883
1884
                if (null !== $event) {
1885
                    return $event;
1886
                }
1887
1888
                if ($agendaCollectiveInvitations) {
1889
                    $eventRepo = Database::getManager()->getRepository('ChamiloCoreBundle:PersonalAgenda');
1890
                    $event = $eventRepo->findOneByIdAndInvitee($id, $user);
1891
1892
                    if ($event && $event->isCollective()) {
1893
                        return [
1894
                            'id' => $event->getId(),
1895
                            'user' => $event->getUser(),
1896
                            'title' => $event->getTitle(),
1897
                            'text' => $event->getText(),
1898
                            'date' => $event->getDate()->format('Y-m-d H:i:s'),
1899
                            'enddate' => $event->getEndDate()->format('Y-m-d H:i:s'),
1900
                            'course' => null,
1901
                            'parent_event_id' => $event->getParentEventId(),
1902
                            'all_day' => $event->getAllDay(),
1903
                            'color' => $event->getColor(),
1904
                            'agenda_event_invitation_id' => $event->getInvitation()->getId(),
1905
                            'collective' => $event->isCollective(),
1906
                            'description' => $event->getText(),
1907
                            'content' => Security::remove_XSS($event->getText(), STUDENT),
1908
                            'start_date' => $event->getDate()->format('Y-m-d H:i:s'),
1909
                            'end_date' => $event->getEndDate()->format('Y-m-d H:i:s'),
1910
                        ];
1911
                    }
1912
                }
1913
1914
                return null;
1915
            case 'course':
1916
                if (!empty($this->course['real_id'])) {
1917
                    $sql = "SELECT * FROM ".$this->tbl_course_agenda."
1918
                            WHERE c_id = ".$this->course['real_id']." AND id = ".$id;
1919
                    $result = Database::query($sql);
1920
                    if (Database::num_rows($result)) {
1921
                        $event = Database::fetch_array($result, 'ASSOC');
1922
                        $event['description'] = Security::remove_XSS($event['content'], STUDENT);
1923
1924
                        // Getting send to array
1925
                        $event['send_to'] = $this->getUsersAndGroupSubscribedToEvent(
1926
                            $id,
1927
                            $this->course['real_id'],
1928
                            $this->sessionId
1929
                        );
1930
1931
                        // Getting repeat info
1932
                        $event['repeat_info'] = $this->getRepeatedInfoByEvent(
1933
                            $id,
1934
                            $this->course['real_id']
1935
                        );
1936
1937
                        if (!empty($event['parent_event_id'])) {
1938
                            $event['parent_info'] = $this->get_event($event['parent_event_id']);
1939
                        }
1940
1941
                        $event['attachment'] = $this->getAttachmentList(
1942
                            $id,
1943
                            $this->course
1944
                        );
1945
                    }
1946
                }
1947
                break;
1948
            case 'admin':
1949
            case 'platform':
1950
                $sql = "SELECT * FROM ".$this->tbl_global_agenda."
1951
                        WHERE id = $id";
1952
                $result = Database::query($sql);
1953
                if (Database::num_rows($result)) {
1954
                    $event = Database::fetch_array($result, 'ASSOC');
1955
                    $event['description'] = Security::remove_XSS($event['content']);
1956
                }
1957
                break;
1958
        }
1959
1960
        return $event;
1961
    }
1962
1963
    /**
1964
     * Gets personal events.
1965
     *
1966
     * @param int $start
1967
     * @param int $end
1968
     *
1969
     * @return array
1970
     */
1971
    public function getPersonalEvents($start, $end)
1972
    {
1973
        $start = (int) $start;
1974
        $end = (int) $end;
1975
        $startDate = null;
1976
        $endDate = null;
1977
        $startCondition = '';
1978
        $endCondition = '';
1979
1980
        $agendaCollectiveInvitations = api_get_configuration_value('agenda_collective_invitations');
1981
        $agendaEventSubscriptions = api_get_configuration_value('agenda_event_subscriptions');
1982
        $userIsAdmin = api_is_platform_admin();
1983
1984
        $queryParams = [];
1985
1986
        if ($start !== 0) {
1987
            $queryParams['start_date'] = api_get_utc_datetime($start, true, true);
1988
            $startCondition = "AND pa.date >= :start_date";
1989
        }
1990
        if ($end !== 0) {
1991
            $queryParams['end_date'] = api_get_utc_datetime($end, false, true);
1992
            $endCondition = "AND (pa.enddate <= :end_date OR pa.enddate IS NULL)";
1993
        }
1994
        $user_id = api_get_user_id();
1995
1996
        $queryParams['user_id'] = $user_id;
1997
        $userCondition = "pa.user = :user_id";
1998
1999
        $objGroup = new UserGroup();
2000
2001
        if ($agendaEventSubscriptions) {
2002
            $groupList = $objGroup->getUserGroupListByUser($user_id, UserGroup::NORMAL_CLASS);
2003
2004
            $userCondition = "(
2005
                    $userCondition
2006
                    OR (
2007
                        pa.subscriptionVisibility = ".AgendaEventSubscription::SUBSCRIPTION_ALL;
2008
2009
            if ($groupList) {
2010
                $userCondition .= "
2011
                        OR (
2012
                            pa.subscriptionVisibility = ".AgendaEventSubscription::SUBSCRIPTION_CLASS."
2013
                            AND pa.subscriptionItemId IN (".implode(', ', array_column($groupList, 'id')).")
2014
                        )
2015
                ";
2016
            }
2017
2018
            $userCondition .= "
2019
                    )
2020
                )
2021
            ";
2022
        }
2023
2024
        $sql = "SELECT pa FROM ChamiloCoreBundle:PersonalAgenda AS pa WHERE $userCondition $startCondition $endCondition";
2025
2026
        $result = Database::getManager()
2027
            ->createQuery($sql)
2028
            ->setParameters($queryParams)
2029
            ->getResult();
2030
2031
        $my_events = [];
2032
2033
        /** @var PersonalAgenda $row */
2034
        foreach ($result as $row) {
2035
            $event = [];
2036
            $event['id'] = 'personal_'.$row->getId();
2037
            $event['title'] = $row->getTitle();
2038
            $event['className'] = 'personal';
2039
            $event['borderColor'] = $event['backgroundColor'] = $this->event_personal_color;
2040
            $event['editable'] = $user_id === (int) $row->getUser();
2041
            $event['sent_to'] = get_lang('Me');
2042
            $event['type'] = 'personal';
2043
2044
            if (!empty($row->getDate())) {
2045
                $event['start'] = $this->formatEventDate($row->getDate());
2046
                $event['start_date_localtime'] = api_get_local_time($row->getDate());
2047
            }
2048
2049
            if (!empty($row->getEnddate())) {
2050
                $event['end'] = $this->formatEventDate($row->getEnddate());
2051
                $event['end_date_localtime'] = api_get_local_time($row->getEnddate());
2052
            }
2053
2054
            $event['description'] = $row->getText();
2055
            $event['allDay'] = $row->getAllDay();
2056
            $event['parent_event_id'] = 0;
2057
            $event['has_children'] = 0;
2058
2059
            if ($agendaCollectiveInvitations || $agendaEventSubscriptions) {
2060
                $subscription = $row->getInvitation();
2061
2062
                if ($subscription instanceof AgendaEventSubscription) {
2063
                    $subscribers = $subscription->getInvitees();
2064
2065
                    $event['subscription_visibility'] = $row->getSubscriptionVisibility();
2066
                    $event['max_subscriptions'] = $subscription->getMaxAttendees();
2067
                    $event['can_subscribe'] = $subscribers->count() < $subscription->getMaxAttendees()
2068
                        || $subscription->getMaxAttendees() === 0;
2069
                    $event['user_is_subscribed'] = $subscription->hasUserAsInvitee(api_get_user_entity($user_id));
2070
                    $event['count_subscribers'] = $subscribers->count();
2071
2072
                    if ($userIsAdmin) {
2073
                        $event['subscribers'] = self::getInviteesForPersonalEvent($row->getId(), AgendaEventSubscriber::class);
2074
                    }
2075
2076
                    if (AgendaEventSubscription::SUBSCRIPTION_CLASS === $row->getSubscriptionVisibility()) {
2077
                        $groupInfo = $objGroup->get($row->getSubscriptionItemId());
2078
                        $event['usergroup'] = $groupInfo['name'];
2079
                    }
2080
                } else {
2081
                    $event['collective'] = $row->isCollective();
2082
                    $event['invitees'] = self::getInviteesForPersonalEvent($row->getId());
2083
                }
2084
            }
2085
2086
            $my_events[] = $event;
2087
            $this->events[] = $event;
2088
        }
2089
2090
        if ($agendaCollectiveInvitations) {
2091
            $this->loadEventsAsInvitee(
2092
                api_get_user_entity($user_id),
2093
                $startDate,
2094
                $endDate
2095
            );
2096
        }
2097
2098
        // Add plugin personal events
2099
2100
        $this->plugin = new AppPlugin();
2101
        $plugins = $this->plugin->getInstalledPluginListObject();
2102
        /** @var Plugin $plugin */
2103
        foreach ($plugins as $plugin) {
2104
            if ($plugin->hasPersonalEvents && method_exists($plugin, 'getPersonalEvents')) {
2105
                $pluginEvents = $plugin->getPersonalEvents($this, $start, $end);
2106
2107
                if (!empty($pluginEvents)) {
2108
                    $this->events = array_merge($this->events, $pluginEvents);
2109
                }
2110
            }
2111
        }
2112
2113
        return $my_events;
2114
    }
2115
2116
    public static function getInviteesForPersonalEvent($eventId, $type = AgendaEventInvitee::class): array
2117
    {
2118
        $em = Database::getManager();
2119
        $event = $em->find('ChamiloCoreBundle:PersonalAgenda', $eventId);
2120
2121
        $invitation = $event->getInvitation();
2122
2123
        if ($invitation instanceof AgendaEventSubscription
2124
            && AgendaEventInvitee::class === $type
2125
        ) {
2126
            return [];
2127
        }
2128
2129
        $inviteeRepo = $em->getRepository($type);
2130
        $invitees = $inviteeRepo->findByInvitation($invitation);
2131
2132
        $inviteeList = [];
2133
2134
        foreach ($invitees as $invitee) {
2135
            $inviteeUser = $invitee->getUser();
2136
            if (!empty($inviteeUser)) {
2137
                $inviteeList[] = [
2138
                    'id' => $inviteeUser->getId(),
2139
                    'name' => $inviteeUser->getCompleteNameWithUsername(),
2140
                ];
2141
            }
2142
        }
2143
2144
        return $inviteeList;
2145
    }
2146
2147
    /**
2148
     * Get user/group list per event.
2149
     *
2150
     * @param int $eventId
2151
     * @param int $courseId
2152
     * @param int $sessionId
2153
     * @paraù int $sessionId
2154
     *
2155
     * @return array
2156
     */
2157
    public function getUsersAndGroupSubscribedToEvent(
2158
        $eventId,
2159
        $courseId,
2160
        $sessionId
2161
    ) {
2162
        $eventId = (int) $eventId;
2163
        $courseId = (int) $courseId;
2164
        $sessionId = (int) $sessionId;
2165
2166
        $sessionCondition = "ip.session_id = $sessionId";
2167
        if (empty($sessionId)) {
2168
            $sessionCondition = " (ip.session_id = 0 OR ip.session_id IS NULL) ";
2169
        }
2170
2171
        $tlb_course_agenda = Database::get_course_table(TABLE_AGENDA);
2172
        $tbl_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
2173
2174
        // Get sent_tos
2175
        $sql = "SELECT DISTINCT to_user_id, to_group_id
2176
                FROM $tbl_property ip
2177
                INNER JOIN $tlb_course_agenda agenda
2178
                ON (
2179
                  ip.ref = agenda.id AND
2180
                  ip.c_id = agenda.c_id AND
2181
                  ip.tool = '".TOOL_CALENDAR_EVENT."'
2182
                )
2183
                WHERE
2184
                    ref = $eventId AND
2185
                    ip.visibility = '1' AND
2186
                    ip.c_id = $courseId AND
2187
                    $sessionCondition
2188
                ";
2189
2190
        $result = Database::query($sql);
2191
        $users = [];
2192
        $groups = [];
2193
        $everyone = false;
2194
2195
        while ($row = Database::fetch_array($result, 'ASSOC')) {
2196
            if (!empty($row['to_group_id'])) {
2197
                $groups[] = $row['to_group_id'];
2198
            }
2199
            if (!empty($row['to_user_id'])) {
2200
                $users[] = $row['to_user_id'];
2201
            }
2202
2203
            if (empty($groups) && empty($users)) {
2204
                if ($row['to_group_id'] == 0) {
2205
                    $everyone = true;
2206
                }
2207
            }
2208
        }
2209
2210
        return [
2211
            'everyone' => $everyone,
2212
            'users' => $users,
2213
            'groups' => $groups,
2214
        ];
2215
    }
2216
2217
    /**
2218
     * @param int    $start
2219
     * @param int    $end
2220
     * @param int    $sessionId
2221
     * @param int    $userId
2222
     * @param string $color
2223
     *
2224
     * @return array
2225
     */
2226
    public function getSessionEvents(
2227
        $start,
2228
        $end,
2229
        $sessionId = 0,
2230
        $userId = 0,
2231
        $color = ''
2232
    ) {
2233
        $courses = SessionManager::get_course_list_by_session_id($sessionId);
2234
2235
        if (!empty($courses)) {
2236
            foreach ($courses as $course) {
2237
                $this->getCourseEvents(
2238
                    $start,
2239
                    $end,
2240
                    $course,
2241
                    0,
2242
                    $sessionId,
2243
                    0,
2244
                    $color
2245
                );
2246
            }
2247
        }
2248
    }
2249
2250
    /**
2251
     * @param int    $start
2252
     * @param int    $end
2253
     * @param array  $courseInfo
2254
     * @param int    $groupId
2255
     * @param int    $sessionId
2256
     * @param int    $user_id
2257
     * @param string $color
2258
     *
2259
     * @return array
2260
     */
2261
    public function getCourseEvents(
2262
        $start,
2263
        $end,
2264
        $courseInfo,
2265
        $groupId = 0,
2266
        $sessionId = 0,
2267
        $user_id = 0,
2268
        $color = ''
2269
    ) {
2270
        $start = isset($start) && !empty($start) ? api_get_utc_datetime(intval($start)) : null;
2271
        $end = isset($end) && !empty($end) ? api_get_utc_datetime(intval($end)) : null;
2272
2273
        if (empty($courseInfo)) {
2274
            return [];
2275
        }
2276
        $courseId = $courseInfo['real_id'];
2277
2278
        if (empty($courseId)) {
2279
            return [];
2280
        }
2281
2282
        $sessionId = (int) $sessionId;
2283
        $user_id = (int) $user_id;
2284
2285
        $groupList = GroupManager::get_group_list(
2286
            null,
2287
            $courseInfo,
2288
            null,
2289
            $sessionId
2290
        );
2291
2292
        $groupNameList = [];
2293
        if (!empty($groupList)) {
2294
            foreach ($groupList as $group) {
2295
                $groupNameList[$group['iid']] = $group['name'];
2296
            }
2297
        }
2298
2299
        if (api_is_platform_admin() || api_is_allowed_to_edit()) {
2300
            $isAllowToEdit = true;
2301
        } else {
2302
            $isAllowToEdit = CourseManager::is_course_teacher(
2303
                api_get_user_id(),
2304
                $courseInfo['code']
2305
            );
2306
        }
2307
2308
        $isAllowToEditByHrm = false;
2309
        if (!empty($sessionId)) {
2310
            $allowDhrToEdit = api_get_configuration_value('allow_agenda_edit_for_hrm');
2311
            if ($allowDhrToEdit) {
2312
                $isHrm = SessionManager::isUserSubscribedAsHRM($sessionId, api_get_user_id());
2313
                if ($isHrm) {
2314
                    $isAllowToEdit = $isAllowToEditByHrm = true;
2315
                }
2316
            }
2317
        }
2318
2319
        $groupMemberships = [];
2320
        if (!empty($groupId)) {
2321
            $groupMemberships = [$groupId];
2322
        } else {
2323
            if ($isAllowToEdit) {
2324
                if (!empty($groupList)) {
2325
                    // c_item_property.to_group_id field was migrated to use
2326
                    // c_group_info.iid
2327
                    $groupMemberships = array_column($groupList, 'iid');
2328
                }
2329
            } else {
2330
                // get only related groups from user
2331
                $groupMemberships = GroupManager::get_group_ids(
2332
                    $courseId,
2333
                    api_get_user_id()
2334
                );
2335
            }
2336
        }
2337
2338
        $tlb_course_agenda = Database::get_course_table(TABLE_AGENDA);
2339
        $tbl_property = Database::get_course_table(TABLE_ITEM_PROPERTY);
2340
2341
        $shareEventsInSessions = 1 == api_get_course_setting('agenda_share_events_in_sessions', $courseInfo);
2342
2343
        $agendaSessionCondition = str_replace(
2344
            ' AND ',
2345
            '',
2346
            api_get_session_condition($sessionId, true, $shareEventsInSessions, 'agenda.session_id')
2347
        );
2348
        $ipSessionCondition = api_get_session_condition($sessionId, true, $shareEventsInSessions, 'ip.session_id');
2349
2350
        $sessionCondition = "($agendaSessionCondition $ipSessionCondition)";
2351
2352
        if ($isAllowToEdit) {
2353
            // No group filter was asked
2354
            if (empty($groupId)) {
2355
                if (empty($user_id)) {
2356
                    // Show all events not added in group
2357
                    $userCondition = ' (ip.to_group_id IS NULL OR ip.to_group_id = 0) ';
2358
                    // admin see only his stuff
2359
                    if ($this->type === 'personal') {
2360
                        $userCondition = " (ip.to_user_id = ".api_get_user_id()." AND (ip.to_group_id IS NULL OR ip.to_group_id = 0) ) ";
2361
                        $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) ) ";
2362
                    }
2363
2364
                    if (!empty($groupMemberships)) {
2365
                        // Show events sent to selected groups
2366
                        $userCondition .= " OR (ip.to_user_id = 0 OR ip.to_user_id is NULL) AND (ip.to_group_id IN (".implode(", ", $groupMemberships).")) ";
2367
                    }
2368
                } else {
2369
                    // Show events of requested user in no group
2370
                    $userCondition = " (ip.to_user_id = $user_id AND (ip.to_group_id IS NULL OR ip.to_group_id = 0)) ";
2371
                    // Show events sent to selected groups
2372
                    if (!empty($groupMemberships)) {
2373
                        $userCondition .= " OR (ip.to_user_id = $user_id) AND (ip.to_group_id IN (".implode(", ", $groupMemberships).")) ";
2374
                    }
2375
                }
2376
            } else {
2377
                // Show only selected groups (depending of user status)
2378
                $userCondition = " (ip.to_user_id = 0 OR ip.to_user_id is NULL) AND (ip.to_group_id IN (".implode(", ", $groupMemberships).")) ";
2379
2380
                if (!empty($groupMemberships)) {
2381
                    // Show send to $user_id in selected groups
2382
                    $userCondition .= " OR (ip.to_user_id = $user_id) AND (ip.to_group_id IN (".implode(", ", $groupMemberships).")) ";
2383
                }
2384
            }
2385
        } else {
2386
            // No group filter was asked
2387
            if (empty($groupId)) {
2388
                // Show events sent to everyone and no group
2389
                $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) ';
2390
2391
                // Show events sent to selected groups
2392
                if (!empty($groupMemberships)) {
2393
                    $userCondition .= " OR (ip.to_user_id = 0 OR ip.to_user_id is NULL) AND (ip.to_group_id IN (".implode(", ", $groupMemberships)."))) ";
2394
                } else {
2395
                    $userCondition .= " ) ";
2396
                }
2397
                $userCondition .= " OR (ip.to_user_id = ".api_get_user_id()." AND (ip.to_group_id IS NULL OR ip.to_group_id = 0)) ";
2398
            } else {
2399
                if (!empty($groupMemberships)) {
2400
                    // Show send to everyone - and only selected groups
2401
                    $userCondition = " (ip.to_user_id = 0 OR ip.to_user_id is NULL) AND (ip.to_group_id IN (".implode(", ", $groupMemberships).")) ";
2402
                }
2403
            }
2404
2405
            // Show sent to only me and no group
2406
            if (!empty($groupMemberships)) {
2407
                $userCondition .= " OR (ip.to_user_id = ".api_get_user_id().") AND (ip.to_group_id IN (".implode(", ", $groupMemberships).")) ";
2408
            } else {
2409
                // Show sent to only me and selected groups
2410
            }
2411
        }
2412
2413
        if (api_is_allowed_to_edit()) {
2414
            $visibilityCondition = " (ip.visibility IN ('1', '0'))  ";
2415
        } else {
2416
            $visibilityCondition = " (ip.visibility = '1') ";
2417
        }
2418
2419
        $sql = "SELECT DISTINCT
2420
                    agenda.*,
2421
                    ip.visibility,
2422
                    ip.to_group_id,
2423
                    ip.insert_user_id,
2424
                    ip.ref,
2425
                    to_user_id
2426
                FROM $tlb_course_agenda agenda
2427
                INNER JOIN $tbl_property ip
2428
                ON (
2429
                    agenda.id = ip.ref AND
2430
                    agenda.c_id = ip.c_id AND
2431
                    ip.tool = '".TOOL_CALENDAR_EVENT."'
2432
                )
2433
                WHERE
2434
                    $sessionCondition AND
2435
                    ($userCondition) AND
2436
                    $visibilityCondition AND
2437
                    agenda.c_id = $courseId
2438
        ";
2439
        $dateCondition = '';
2440
        if (!empty($start) && !empty($end)) {
2441
            $dateCondition .= "AND (
2442
                 agenda.start_date BETWEEN '".$start."' AND '".$end."' OR
2443
                 agenda.end_date BETWEEN '".$start."' AND '".$end."' OR
2444
                 (
2445
                     agenda.start_date IS NOT NULL AND agenda.end_date IS NOT NULL AND
2446
                     YEAR(agenda.start_date) = YEAR(agenda.end_date) AND
2447
                     MONTH('$start') BETWEEN MONTH(agenda.start_date) AND MONTH(agenda.end_date)
2448
                 )
2449
            )";
2450
        }
2451
2452
        $sql .= $dateCondition;
2453
        $result = Database::query($sql);
2454
2455
        $coachCanEdit = false;
2456
        if (!empty($sessionId)) {
2457
            $coachCanEdit = api_is_coach($sessionId, $courseId) || api_is_platform_admin();
2458
        }
2459
2460
        if (Database::num_rows($result)) {
2461
            $eventsAdded = array_column($this->events, 'unique_id');
2462
            while ($row = Database::fetch_array($result, 'ASSOC')) {
2463
                $event = [];
2464
                $event['id'] = 'course_'.$row['id'];
2465
                $event['unique_id'] = $row['iid'];
2466
                // To avoid doubles
2467
                if (in_array($event['unique_id'], $eventsAdded)) {
2468
                    continue;
2469
                }
2470
2471
                $eventsAdded[] = $event['unique_id'];
2472
                $eventId = $row['ref'];
2473
                $items = $this->getUsersAndGroupSubscribedToEvent(
2474
                    $eventId,
2475
                    $courseId,
2476
                    $this->sessionId
2477
                );
2478
                $group_to_array = $items['groups'];
2479
                $user_to_array = $items['users'];
2480
                $attachmentList = $this->getAttachmentList(
2481
                    $row['id'],
2482
                    $courseInfo
2483
                );
2484
                $event['attachment'] = '';
2485
                if (!empty($attachmentList)) {
2486
                    foreach ($attachmentList as $attachment) {
2487
                        $has_attachment = Display::return_icon(
2488
                            'attachment.gif',
2489
                            get_lang('Attachment')
2490
                        );
2491
                        $user_filename = $attachment['filename'];
2492
                        $url = api_get_path(WEB_CODE_PATH).'calendar/download.php?file='.$attachment['path'].'&course_id='.$courseId.'&'.api_get_cidreq();
2493
                        $event['attachment'] .= $has_attachment.
2494
                            Display::url(
2495
                                $user_filename,
2496
                                $url
2497
                            ).'<br />';
2498
                    }
2499
                }
2500
2501
                $event['title'] = $row['title'];
2502
                $event['className'] = 'course';
2503
                $event['allDay'] = 'false';
2504
                $event['course_id'] = $courseId;
2505
                $event['borderColor'] = $event['backgroundColor'] = $this->event_course_color;
2506
2507
                $sessionInfo = [];
2508
                if (isset($row['session_id']) && !empty($row['session_id'])) {
2509
                    $sessionInfo = api_get_session_info($sessionId);
2510
                    $event['borderColor'] = $event['backgroundColor'] = $this->event_session_color;
2511
                }
2512
2513
                $event['session_name'] = isset($sessionInfo['name']) ? $sessionInfo['name'] : '';
2514
                $event['course_name'] = isset($courseInfo['title']) ? $courseInfo['title'] : '';
2515
2516
                if (isset($row['to_group_id']) && !empty($row['to_group_id'])) {
2517
                    $event['borderColor'] = $event['backgroundColor'] = $this->event_group_color;
2518
                }
2519
2520
                if (!empty($color)) {
2521
                    $event['borderColor'] = $event['backgroundColor'] = $color;
2522
                }
2523
2524
                if (isset($row['color']) && !empty($row['color'])) {
2525
                    $event['borderColor'] = $event['backgroundColor'] = $row['color'];
2526
                }
2527
2528
                $event['editable'] = false;
2529
                if ($this->getIsAllowedToEdit() && $this->type == 'course') {
2530
                    $event['editable'] = true;
2531
                    if (!empty($sessionId)) {
2532
                        if ($coachCanEdit == false) {
2533
                            $event['editable'] = false;
2534
                        }
2535
                        if ($isAllowToEditByHrm) {
2536
                            $event['editable'] = true;
2537
                        }
2538
                        if ($sessionId != $row['session_id']) {
2539
                            $event['editable'] = false;
2540
                        }
2541
                    }
2542
                    // if user is author then he can edit the item
2543
                    if (api_get_user_id() == $row['insert_user_id']) {
2544
                        $event['editable'] = true;
2545
                    }
2546
                }
2547
2548
                if (!empty($row['start_date'])) {
2549
                    $event['start'] = $this->formatEventDate($row['start_date']);
2550
                    $event['start_date_localtime'] = api_get_local_time($row['start_date']);
2551
                }
2552
                if (!empty($row['end_date'])) {
2553
                    $event['end'] = $this->formatEventDate($row['end_date']);
2554
                    $event['end_date_localtime'] = api_get_local_time($row['end_date']);
2555
                }
2556
2557
                $event['sent_to'] = '';
2558
                $event['type'] = 'course';
2559
                if ($row['session_id'] != 0) {
2560
                    $event['type'] = 'session';
2561
                }
2562
2563
                // Event Sent to a group?
2564
                if (isset($row['to_group_id']) && !empty($row['to_group_id'])) {
2565
                    $sent_to = [];
2566
                    if (!empty($group_to_array)) {
2567
                        foreach ($group_to_array as $group_item) {
2568
                            $sent_to[] = $groupNameList[$group_item];
2569
                        }
2570
                    }
2571
                    $sent_to = implode('@@', $sent_to);
2572
                    $sent_to = str_replace(
2573
                        '@@',
2574
                        '</div><div class="label_tag notice">',
2575
                        $sent_to
2576
                    );
2577
                    $event['sent_to'] = '<div class="label_tag notice">'.$sent_to.'</div>';
2578
                    $event['type'] = 'group';
2579
                    $event['group_id'] = $row['to_group_id'];
2580
                }
2581
2582
                // Event sent to a user?
2583
                if (isset($row['to_user_id'])) {
2584
                    $sent_to = [];
2585
                    if (!empty($user_to_array)) {
2586
                        foreach ($user_to_array as $item) {
2587
                            $user_info = api_get_user_info($item);
2588
                            // Add username as tooltip for $event['sent_to'] - ref #4226
2589
                            $username = api_htmlentities(
2590
                                sprintf(
2591
                                    get_lang('LoginX'),
2592
                                    $user_info['username']
2593
                                ),
2594
                                ENT_QUOTES
2595
                            );
2596
                            $sent_to[] = "<span title='".$username."'>".$user_info['complete_name']."</span>";
2597
                        }
2598
                    }
2599
                    $sent_to = implode('@@', $sent_to);
2600
                    $sent_to = str_replace(
2601
                        '@@',
2602
                        '</div><div class="label_tag notice">',
2603
                        $sent_to
2604
                    );
2605
                    $event['sent_to'] = '<div class="label_tag notice">'.$sent_to.'</div>';
2606
                }
2607
2608
                //Event sent to everyone!
2609
                if (empty($event['sent_to'])) {
2610
                    $event['sent_to'] = '<div class="label_tag notice">'.get_lang('Everyone').'</div>';
2611
                }
2612
2613
                $event['description'] = Security::remove_XSS($row['content']);
2614
                $event['visibility'] = $row['visibility'];
2615
                $event['real_id'] = $row['id'];
2616
                $event['allDay'] = isset($row['all_day']) && $row['all_day'] == 1 ? $row['all_day'] : 0;
2617
                $event['parent_event_id'] = $row['parent_event_id'];
2618
                $event['has_children'] = $this->hasChildren($row['id'], $courseId) ? 1 : 0;
2619
                $event['comment'] = Security::remove_XSS($row['comment']);
2620
                $this->events[] = $event;
2621
            }
2622
        }
2623
2624
        return $this->events;
2625
    }
2626
2627
    /**
2628
     * @param int $start tms
2629
     * @param int $end   tms
2630
     *
2631
     * @return array
2632
     */
2633
    public function getPlatformEvents($start, $end)
2634
    {
2635
        $start = isset($start) && !empty($start) ? api_get_utc_datetime(intval($start)) : null;
2636
        $end = isset($end) && !empty($end) ? api_get_utc_datetime(intval($end)) : null;
2637
        $dateCondition = '';
2638
2639
        if (!empty($start) && !empty($end)) {
2640
            $dateCondition .= "AND (
2641
                 start_date BETWEEN '".$start."' AND '".$end."' OR
2642
                 end_date BETWEEN '".$start."' AND '".$end."' OR
2643
                 (
2644
                     start_date IS NOT NULL AND end_date IS NOT NULL AND
2645
                     YEAR(start_date) = YEAR(end_date) AND
2646
                     MONTH('$start') BETWEEN MONTH(start_date) AND MONTH(end_date)
2647
                 )
2648
            )";
2649
        }
2650
2651
        $access_url_id = api_get_current_access_url_id();
2652
2653
        $sql = "SELECT *
2654
                FROM ".$this->tbl_global_agenda."
2655
                WHERE access_url_id = $access_url_id
2656
                $dateCondition";
2657
        $result = Database::query($sql);
2658
2659
        if (!Database::num_rows($result)) {
2660
            return [];
2661
        }
2662
2663
        $my_events = [];
2664
        $allowCareersInGlobalAgenda = api_get_configuration_value('allow_careers_in_global_agenda');
2665
        $userId = api_get_user_id();
2666
        $userVisibility = SystemAnnouncementManager::getCurrentUserVisibility();
2667
2668
        while ($row = Database::fetch_array($result, 'ASSOC')) {
2669
            $event = [];
2670
            $event['id'] = 'platform_'.$row['id'];
2671
            $event['title'] = $row['title'];
2672
            $event['className'] = 'platform';
2673
            $event['allDay'] = 'false';
2674
            $event['borderColor'] = $event['backgroundColor'] = $this->event_platform_color;
2675
            $event['editable'] = false;
2676
            $event['type'] = 'admin';
2677
2678
            if (api_is_platform_admin() && $this->type === 'admin') {
2679
                $event['editable'] = true;
2680
            }
2681
2682
            if (!empty($row['start_date'])) {
2683
                $event['start'] = $this->formatEventDate($row['start_date']);
2684
                $event['start_date_localtime'] = api_get_local_time($row['start_date']);
2685
            }
2686
2687
            if (!empty($row['end_date'])) {
2688
                $event['end'] = $this->formatEventDate($row['end_date']);
2689
                $event['end_date_localtime'] = api_get_local_time($row['end_date']);
2690
            }
2691
            $event['allDay'] = isset($row['all_day']) && $row['all_day'] == 1 ? $row['all_day'] : 0;
2692
            $event['parent_event_id'] = 0;
2693
            $event['has_children'] = 0;
2694
            $event['description'] = $row['content'];
2695
2696
            if ($allowCareersInGlobalAgenda) {
2697
                $event['career'] = null;
2698
                $event['promotion'] = null;
2699
2700
                $careerId = (int) $row['career_id'];
2701
                $promotionId = (int) $row['promotion_id'];
2702
2703
                $careerPromotionEventIsVisibleForUser = true;
2704
2705
                if (($careerId || $promotionId) && 'admin' !== $this->type) {
2706
                    $careerPromotionEventIsVisibleForUser = SystemAnnouncementManager::isVisibleAnnouncementForUser(
2707
                        $userId,
2708
                        $userVisibility,
2709
                        $careerId,
2710
                        $promotionId
2711
                    );
2712
                }
2713
2714
                if (false === $careerPromotionEventIsVisibleForUser) {
2715
                    continue;
2716
                }
2717
2718
                if (0 !== $careerId) {
2719
                    $careerInfo = (new Career())->get($row['career_id']);
2720
2721
                    unset($careerInfo['status'], $careerInfo['created_at'], $careerInfo['updated_at']);
2722
2723
                    $event['career'] = $careerInfo;
2724
                }
2725
2726
                if (0 !== $promotionId) {
2727
                    $promotionInfo = (new Promotion())->get($row['promotion_id']);
2728
2729
                    unset(
2730
                        $promotionInfo['career_id'],
2731
                        $promotionInfo['status'],
2732
                        $promotionInfo['created_at'],
2733
                        $promotionInfo['updated_at']
2734
                    );
2735
2736
                    $event['promotion'] = $promotionInfo;
2737
                }
2738
            }
2739
2740
            $my_events[] = $event;
2741
            $this->events[] = $event;
2742
        }
2743
2744
        return $my_events;
2745
    }
2746
2747
    /**
2748
     * @param FormValidator $form
2749
     * @param array         $groupList
2750
     * @param array         $userList
2751
     * @param array         $sendTo               array('users' => [1, 2], 'groups' => [3, 4])
2752
     * @param array         $attributes
2753
     * @param bool          $addOnlyItemsInSendTo
2754
     * @param bool          $required
2755
     */
2756
    public function setSendToSelect(
2757
        $form,
2758
        $groupList = [],
2759
        $userList = [],
2760
        $sendTo = [],
2761
        $attributes = [],
2762
        $addOnlyItemsInSendTo = false,
2763
        $required = false
2764
    ) {
2765
        $params = [
2766
            'id' => 'users_to_send_id',
2767
            'data-placeholder' => get_lang('Select'),
2768
            'multiple' => 'multiple',
2769
            'class' => 'multiple-select',
2770
        ];
2771
2772
        if (!empty($attributes)) {
2773
            $params = array_merge($params, $attributes);
2774
            if (empty($params['multiple'])) {
2775
                unset($params['multiple']);
2776
            }
2777
        }
2778
2779
        $sendToGroups = isset($sendTo['groups']) ? $sendTo['groups'] : [];
2780
        $sendToUsers = isset($sendTo['users']) ? $sendTo['users'] : [];
2781
2782
        /** @var HTML_QuickForm_select $select */
2783
        $select = $form->addSelect(
2784
            'users_to_send',
2785
            get_lang('To'),
2786
            null,
2787
            $params
2788
        );
2789
2790
        if ($required) {
2791
            $form->setRequired($select);
2792
        }
2793
2794
        $selectedEveryoneOptions = [];
2795
        if (isset($sendTo['everyone']) && $sendTo['everyone']) {
2796
            $selectedEveryoneOptions = ['selected'];
2797
            $sendToUsers = [];
2798
        }
2799
2800
        $select->addOption(
2801
            get_lang('Everyone'),
2802
            'everyone',
2803
            $selectedEveryoneOptions
2804
        );
2805
2806
        $options = [];
2807
        if (is_array($groupList)) {
2808
            foreach ($groupList as $group) {
2809
                $count_users = isset($group['count_users']) ? $group['count_users'] : $group['userNb'];
2810
                $count_users = " &ndash; $count_users ".get_lang('Users');
2811
                $option = [
2812
                    'text' => $group['name'].$count_users,
2813
                    'value' => "GROUP:".$group['id'],
2814
                ];
2815
                $selected = in_array(
2816
                    $group['id'],
2817
                    $sendToGroups
2818
                ) ? true : false;
2819
                if ($selected) {
2820
                    $option['selected'] = 'selected';
2821
                }
2822
2823
                if ($addOnlyItemsInSendTo) {
2824
                    if ($selected) {
2825
                        $options[] = $option;
2826
                    }
2827
                } else {
2828
                    $options[] = $option;
2829
                }
2830
            }
2831
            $select->addOptGroup($options, get_lang('Groups'));
2832
        }
2833
2834
        // adding the individual users to the select form
2835
        if (is_array($userList)) {
2836
            $options = [];
2837
            foreach ($userList as $user) {
2838
                if ($user['status'] == ANONYMOUS) {
2839
                    continue;
2840
                }
2841
                $option = [
2842
                    'text' => api_get_person_name(
2843
                            $user['firstname'],
2844
                            $user['lastname']
2845
                        ).' ('.$user['username'].')',
2846
                    'value' => "USER:".$user['user_id'],
2847
                ];
2848
2849
                $selected = in_array(
2850
                    $user['user_id'],
2851
                    $sendToUsers
2852
                ) ? true : false;
2853
2854
                if ($selected) {
2855
                    $option['selected'] = 'selected';
2856
                }
2857
2858
                if ($addOnlyItemsInSendTo) {
2859
                    if ($selected) {
2860
                        $options[] = $option;
2861
                    }
2862
                } else {
2863
                    $options[] = $option;
2864
                }
2865
            }
2866
2867
            $select->addOptGroup($options, get_lang('Users'));
2868
        }
2869
    }
2870
2871
    /**
2872
     * Separates the users and groups array
2873
     * users have a value USER:XXX (with XXX the user id
2874
     * groups have a value GROUP:YYY (with YYY the group id)
2875
     * use the 'everyone' key.
2876
     *
2877
     * @author Julio Montoya based in separate_users_groups in agenda.inc.php
2878
     *
2879
     * @param array $to
2880
     *
2881
     * @return array
2882
     */
2883
    public function parseSendToArray($to)
2884
    {
2885
        $groupList = [];
2886
        $userList = [];
2887
        $sendTo = null;
2888
2889
        $sendTo['everyone'] = false;
2890
        if (is_array($to) && count($to) > 0) {
2891
            foreach ($to as $item) {
2892
                if ($item == 'everyone') {
2893
                    $sendTo['everyone'] = true;
2894
                } else {
2895
                    list($type, $id) = explode(':', $item);
2896
                    switch ($type) {
2897
                        case 'GROUP':
2898
                            $groupList[] = $id;
2899
                            break;
2900
                        case 'USER':
2901
                            $userList[] = $id;
2902
                            break;
2903
                    }
2904
                }
2905
            }
2906
            $sendTo['groups'] = $groupList;
2907
            $sendTo['users'] = $userList;
2908
        }
2909
2910
        return $sendTo;
2911
    }
2912
2913
    /**
2914
     * @param int    $eventId
2915
     * @param string $type
2916
     *
2917
     * @return array<int, AgendaReminder>
2918
     */
2919
    public function getEventReminders($eventId, $type = null): array
2920
    {
2921
        $em = Database::getManager();
2922
        $remindersRepo = $em->getRepository('ChamiloCoreBundle:AgendaReminder');
2923
2924
        return $remindersRepo->findBy(
2925
            [
2926
                'eventId' => $eventId,
2927
                'type' => $type ?: $this->type,
2928
            ]
2929
        );
2930
    }
2931
2932
    public function parseEventReminders(array $eventReminders): array
2933
    {
2934
        return array_map(
2935
            function (AgendaReminder $reminder) {
2936
                $interval = $reminder->getDateInterval();
2937
2938
                $reminderInfo = [
2939
                    'id' => $reminder->getId(),
2940
                    'type' => $reminder->getType(),
2941
                    'sent' => $reminder->isSent(),
2942
                    'date_interval' => [$interval->format('%a'), 'd'],
2943
                ];
2944
2945
                if ($interval->i) {
2946
                    $reminderInfo['date_interval'] = [$interval->i, 'i'];
2947
                } elseif ($interval->h) {
2948
                    $reminderInfo['date_interval'] = [$interval->h, 'h'];
2949
                } elseif ($interval->d) {
2950
                    $reminderInfo['date_interval'] = [$interval->d, 'd'];
2951
                }
2952
2953
                return $reminderInfo;
2954
            },
2955
            $eventReminders
2956
        );
2957
    }
2958
2959
    /**
2960
     * @param array $params
2961
     *
2962
     * @return FormValidator
2963
     */
2964
    public function getForm($params = [])
2965
    {
2966
        $action = isset($params['action']) ? Security::remove_XSS($params['action']) : null;
2967
        $id = isset($params['id']) ? (int) $params['id'] : 0;
2968
2969
        $em = Database::getManager();
2970
        $personalEvent = 'personal' === $this->type && $id ? $em->find('ChamiloCoreBundle:PersonalAgenda', $id) : null;
2971
2972
        $url = api_get_self().'?action='.$action.'&id='.$id.'&type='.$this->type;
2973
        if ($this->type == 'course') {
2974
            $url = api_get_self().'?'.api_get_cidreq().'&action='.$action.'&id='.$id.'&type='.$this->type;
2975
        }
2976
2977
        $form = new FormValidator(
2978
            'add_event',
2979
            'post',
2980
            $url,
2981
            null,
2982
            ['enctype' => 'multipart/form-data']
2983
        );
2984
2985
        $idAttach = isset($params['id_attach']) ? (int) $params['id_attach'] : null;
2986
        $groupId = api_get_group_id();
2987
        $form_Title = get_lang('AddCalendarItem');
2988
        if (!empty($id)) {
2989
            $form_Title = get_lang('ModifyCalendarItem');
2990
        }
2991
2992
        $form->addHeader($form_Title);
2993
        $form->addElement('hidden', 'id', $id);
2994
        $form->addElement('hidden', 'action', $action);
2995
        $form->addElement('hidden', 'id_attach', $idAttach);
2996
2997
        $isSubEventEdition = false;
2998
        $isParentFromSerie = false;
2999
        $showAttachmentForm = true;
3000
3001
        if ($this->type == 'course') {
3002
            // Edition mode.
3003
            if (!empty($id)) {
3004
                $showAttachmentForm = false;
3005
                if (isset($params['parent_event_id']) && !empty($params['parent_event_id'])) {
3006
                    $isSubEventEdition = true;
3007
                }
3008
                if (!empty($params['repeat_info'])) {
3009
                    $isParentFromSerie = true;
3010
                }
3011
            }
3012
        }
3013
3014
        if ($isSubEventEdition) {
3015
            $form->addElement(
3016
                'label',
3017
                null,
3018
                Display::return_message(
3019
                    get_lang('EditingThisEventWillRemoveItFromTheSerie'),
3020
                    'warning'
3021
                )
3022
            );
3023
        }
3024
3025
        $form->addElement('text', 'title', get_lang('ItemTitle'));
3026
3027
        if (isset($groupId) && !empty($groupId)) {
3028
            $form->addElement(
3029
                'hidden',
3030
                'users_to_send[]',
3031
                "GROUP:$groupId"
3032
            );
3033
            $form->addElement('hidden', 'to', 'true');
3034
        } else {
3035
            $defaultSendTo = ['everyone' => true];
3036
            if (api_get_configuration_value('course_agenda_set_default_send_to_with_none')) {
3037
                $defaultSendTo = ['everyone' => false];
3038
            }
3039
            $defaultSendToCurrentUser = '';
3040
            if (api_get_configuration_value('course_agenda_set_default_send_to_with_current_user')) {
3041
                $defaultSendToCurrentUser = api_get_user_id();
3042
            }
3043
            if (api_get_configuration_value('course_agenda_set_default_send_to_with_teachers')) {
3044
                $currentCourseInfo = api_get_course_info();
3045
                $sessionId = api_get_session_id();
3046
                if ($sessionId) {
3047
                    $usersSendTo = SessionManager::getCoachesByCourseSession($sessionId, $currentCourseInfo['real_id']);
3048
                } else {
3049
                    $courseTeachers = CourseManager::get_teacher_list_from_course_code($currentCourseInfo['code']);
3050
                    $courseTeachersUid = [];
3051
                    foreach ($courseTeachers as $courseTeacher) {
3052
                        $courseTeachersUid[] = $courseTeacher['user_id'];
3053
                    }
3054
                    $usersSendTo = $courseTeachersUid;
3055
                }
3056
                $usersSendTo[] = $defaultSendToCurrentUser;
3057
                $defaultSendTo = ['users' => $usersSendTo];
3058
            } elseif ($defaultSendToCurrentUser) {
3059
                $defaultSendTo = ['users' => [$defaultSendToCurrentUser]];
3060
            }
3061
            $sendTo = isset($params['send_to']) ? $params['send_to'] : $defaultSendTo;
3062
3063
            if ($this->type == 'course') {
3064
                $this->showToForm($form, $sendTo, [], false, true);
3065
            }
3066
        }
3067
3068
        $form->addDateRangePicker(
3069
            'date_range',
3070
            get_lang('DateRange'),
3071
            false,
3072
            ['id' => 'date_range']
3073
        );
3074
        $form->addElement('checkbox', 'all_day', null, get_lang('AllDay'));
3075
3076
        if ($this->type == 'course') {
3077
            $repeat = $form->addElement(
3078
                'checkbox',
3079
                'repeat',
3080
                null,
3081
                get_lang('RepeatEvent'),
3082
                ['onclick' => 'return plus_repeated_event();']
3083
            );
3084
            $form->addElement(
3085
                'html',
3086
                '<div id="options2" style="display:none">'
3087
            );
3088
            $form->addElement(
3089
                'select',
3090
                'repeat_type',
3091
                get_lang('RepeatType'),
3092
                self::getRepeatTypes()
3093
            );
3094
            $form->addElement(
3095
                'date_picker',
3096
                'repeat_end_day',
3097
                get_lang('RepeatEnd'),
3098
                ['id' => 'repeat_end_date_form']
3099
            );
3100
3101
            if ($isSubEventEdition || $isParentFromSerie) {
3102
                $repeatInfo = $params['repeat_info'];
3103
                if ($isSubEventEdition) {
3104
                    $parentEvent = $params['parent_info'];
3105
                    $repeatInfo = $parentEvent['repeat_info'];
3106
                }
3107
                $params['repeat'] = 1;
3108
                $params['repeat_type'] = $repeatInfo['cal_type'];
3109
                $params['repeat_end_day'] = substr(
3110
                    api_get_local_time($repeatInfo['cal_end']),
3111
                    0,
3112
                    10
3113
                );
3114
3115
                $form->freeze(['repeat_type', 'repeat_end_day']);
3116
                $repeat->_attributes['disabled'] = 'disabled';
3117
            }
3118
            $form->addElement('html', '</div>');
3119
        }
3120
3121
        if (!empty($id)) {
3122
            if (empty($params['end_date'])) {
3123
                $params['date_range'] = $params['end_date'];
3124
            }
3125
3126
            $params['date_range'] =
3127
                substr(api_get_local_time($params['start_date']), 0, 16).' / '.
3128
                substr(api_get_local_time($params['end_date']), 0, 16);
3129
        }
3130
3131
        $toolbar = 'Agenda';
3132
        if (!api_is_allowed_to_edit(null, true)) {
3133
            $toolbar = 'AgendaStudent';
3134
        }
3135
3136
        $form->addHtmlEditor(
3137
            'content',
3138
            get_lang('Description'),
3139
            false,
3140
            false,
3141
            [
3142
                'style' => 'vertical-align:middle;',
3143
                'ToolbarSet' => $toolbar,
3144
                'Width' => '100%',
3145
                'Height' => '200',
3146
            ]
3147
        );
3148
3149
        if ($this->type == 'course') {
3150
            $form->addElement('textarea', 'comment', get_lang('Comment'));
3151
            $form->addLabel(
3152
                get_lang('FilesAttachment'),
3153
                '<div id="filepaths" class="file-upload-event">
3154
3155
                        <div id="filepath_1">
3156
                            <input type="file" name="attach_1"/>
3157
3158
                            <label>'.get_lang('Description').'</label>
3159
                            <input class="form-control" type="text" name="legend[]" />
3160
                        </div>
3161
3162
                    </div>'
3163
            );
3164
3165
            $form->addLabel(
3166
                '',
3167
                '<span id="link-more-attach">
3168
                    <a href="javascript://" onclick="return add_image_form()">'.
3169
                get_lang('AddOneMoreFile').'</a>
3170
                 </span>&nbsp;('.sprintf(
3171
                    get_lang('MaximunFileSizeX'),
3172
                    format_file_size(
3173
                        api_get_setting('message_max_upload_filesize')
3174
                    )
3175
                ).')'
3176
            );
3177
3178
            if (isset($params['attachment']) && !empty($params['attachment'])) {
3179
                $attachmentList = $params['attachment'];
3180
                foreach ($attachmentList as $attachment) {
3181
                    $params['file_comment'] = $attachment['comment'];
3182
                    if (!empty($attachment['path'])) {
3183
                        $form->addElement(
3184
                            'checkbox',
3185
                            'delete_attachment['.$attachment['id'].']',
3186
                            null,
3187
                            get_lang(
3188
                                'DeleteAttachment'
3189
                            ).': '.$attachment['filename']
3190
                        );
3191
                    }
3192
                }
3193
            }
3194
3195
            $form->addElement(
3196
                'textarea',
3197
                'file_comment',
3198
                get_lang('FileComment')
3199
            );
3200
        }
3201
3202
        if (empty($id) && 'course' === $this->type) {
3203
            $form->addElement(
3204
                'checkbox',
3205
                'add_announcement',
3206
                null,
3207
                get_lang('AddAnnouncement').'&nbsp('.get_lang('SendMail').')'
3208
            );
3209
        }
3210
3211
        $agendaCollectiveInvitations = api_get_configuration_value('agenda_collective_invitations');
3212
        $agendaEventSubscriptions = api_is_platform_admin()
3213
            && true === api_get_configuration_value('agenda_event_subscriptions');
3214
3215
        $allowCollectiveInvitations = $agendaCollectiveInvitations && 'personal' === $this->type;
3216
        $allowEventSubscriptions = 'personal' === $this->type && $agendaEventSubscriptions;
3217
3218
        if ($allowCollectiveInvitations && $allowEventSubscriptions && !$personalEvent) {
3219
            $form->addRadio(
3220
                'invitation_type',
3221
                get_lang('Allowed'),
3222
                [
3223
                    'invitations' => get_lang('Invitations'),
3224
                    'subscriptions' => get_lang('Subscriptions'),
3225
                ],
3226
                [
3227
                    'onchange' => "$('#invitations-block, #subscriptions-block').hide(); $('#' + this.value + '-block').show();",
3228
                ]
3229
            );
3230
        }
3231
3232
        if ($allowCollectiveInvitations) {
3233
            $this->addCollectiveInvitationsFields($form, $personalEvent);
3234
        }
3235
3236
        if ($agendaEventSubscriptions) {
3237
            $this->addSubscriptionFields($form, $personalEvent);
3238
        }
3239
3240
        if (api_get_configuration_value('agenda_reminders')) {
3241
            $form->addHtml('<div id="notification_list">');
3242
3243
            if ($id) {
3244
                $this->addFieldsForRemindersToForm($id, $form);
3245
            }
3246
3247
            $form->addHtml('</div>');
3248
            $form->addButton('add_notification', get_lang('AddNotification'), 'bell-o')->setType('button');
3249
            $form->addHtml('<hr>');
3250
        }
3251
3252
        if (api_get_configuration_value('allow_careers_in_global_agenda') && 'admin' === $this->type) {
3253
            Career::addCareerFieldsToForm($form);
3254
            $form->addHtml('<hr>');
3255
        }
3256
3257
        if ($id) {
3258
            $form->addButtonUpdate(get_lang('ModifyEvent'));
3259
        } else {
3260
            $form->addButtonSave(get_lang('AgendaAdd'));
3261
        }
3262
3263
        $form->setDefaults($params);
3264
        $form->addRule(
3265
            'date_range',
3266
            get_lang('ThisFieldIsRequired'),
3267
            'required'
3268
        );
3269
        $form->addRule('title', get_lang('ThisFieldIsRequired'), 'required');
3270
3271
        return $form;
3272
    }
3273
3274
    public function addFieldsForRemindersToForm(int $eventId, FormValidator $form)
3275
    {
3276
        $remindersList = $this->parseEventReminders(
3277
            $this->getEventReminders($eventId)
3278
        );
3279
3280
        foreach ($remindersList as $reminderInfo) {
3281
            $form->addHtml('<div class="form-group">');
3282
            $form
3283
                ->addNumeric('notification_count[]', '', ['step' => 1, 'min' => 0])
3284
                ->setValue($reminderInfo['date_interval'][0])
3285
            ;
3286
            $form
3287
                ->addSelect(
3288
                'notification_period[]',
3289
                '',
3290
                    [
3291
                        'i' => get_lang('Minutes'),
3292
                        'h' => get_lang('Hours'),
3293
                        'd' => get_lang('Days'),
3294
                    ]
3295
                )
3296
                ->setValue($reminderInfo['date_interval'][1])
3297
            ;
3298
            $form->addHtml('<div class="col-sm-2"><p class="form-control-static">'.get_lang('Before').'</p></div>');
3299
            $form->addHtml(
3300
                '<div class="text-right col-sm-2">'
3301
                .'<button class="btn btn-default delete-notification" type="button" aria-label="'.get_lang('Delete').'"><em class="fa fa-times"></em></button>'
3302
                .'</div>'
3303
            );
3304
            $form->addHtml('</div>');
3305
        }
3306
3307
        $renderer = $form->defaultRenderer();
3308
        $renderer->setElementTemplate(
3309
            '<div class="col-sm-offset-2 col-sm-3">{element}</div>',
3310
            'notification_count[]'
3311
        );
3312
        $renderer->setElementTemplate(
3313
            '<div class="col-sm-3">{element}</div>',
3314
            'notification_period[]'
3315
        );
3316
    }
3317
3318
    /**
3319
     * @param FormValidator $form
3320
     * @param array         $sendTo               array('everyone' => false, 'users' => [1, 2], 'groups' => [3, 4])
3321
     * @param array         $attributes
3322
     * @param bool          $addOnlyItemsInSendTo
3323
     * @param bool          $required
3324
     *
3325
     * @return bool
3326
     */
3327
    public function showToForm(
3328
        $form,
3329
        $sendTo = [],
3330
        $attributes = [],
3331
        $addOnlyItemsInSendTo = false,
3332
        $required = false
3333
    ) {
3334
        if ($this->type != 'course') {
3335
            return false;
3336
        }
3337
3338
        $order = 'lastname';
3339
        if (api_is_western_name_order()) {
3340
            $order = 'firstname';
3341
        }
3342
3343
        $userList = CourseManager::get_user_list_from_course_code(
3344
            api_get_course_id(),
3345
            $this->sessionId,
3346
            null,
3347
            $order
3348
        );
3349
3350
        $groupList = CourseManager::get_group_list_of_course(
3351
            api_get_course_id(),
3352
            $this->sessionId
3353
        );
3354
3355
        $this->setSendToSelect(
3356
            $form,
3357
            $groupList,
3358
            $userList,
3359
            $sendTo,
3360
            $attributes,
3361
            $addOnlyItemsInSendTo,
3362
            $required
3363
        );
3364
3365
        return true;
3366
    }
3367
3368
    /**
3369
     * @param int   $id
3370
     * @param int   $visibility 0= invisible, 1 visible
3371
     * @param array $courseInfo
3372
     * @param int   $userId
3373
     */
3374
    public static function changeVisibility(
3375
        $id,
3376
        $visibility,
3377
        $courseInfo,
3378
        $userId = null
3379
    ) {
3380
        $id = intval($id);
3381
        if (empty($userId)) {
3382
            $userId = api_get_user_id();
3383
        } else {
3384
            $userId = intval($userId);
3385
        }
3386
3387
        if ($visibility == 0) {
3388
            api_item_property_update(
3389
                $courseInfo,
3390
                TOOL_CALENDAR_EVENT,
3391
                $id,
3392
                'invisible',
3393
                $userId
3394
            );
3395
        } else {
3396
            api_item_property_update(
3397
                $courseInfo,
3398
                TOOL_CALENDAR_EVENT,
3399
                $id,
3400
                'visible',
3401
                $userId
3402
            );
3403
        }
3404
    }
3405
3406
    /**
3407
     * Get repeat types.
3408
     *
3409
     * @return array
3410
     */
3411
    public static function getRepeatTypes()
3412
    {
3413
        return [
3414
            'daily' => get_lang('RepeatDaily'),
3415
            'weekly' => get_lang('RepeatWeekly'),
3416
            'monthlyByDate' => get_lang('RepeatMonthlyByDate'),
3417
            //monthlyByDay"> get_lang('RepeatMonthlyByDay');
3418
            //monthlyByDayR' => get_lang('RepeatMonthlyByDayR'),
3419
            'yearly' => get_lang('RepeatYearly'),
3420
        ];
3421
    }
3422
3423
    /**
3424
     * Show a list with all the attachments according to the post's id.
3425
     *
3426
     * @param int   $eventId
3427
     * @param array $courseInfo
3428
     *
3429
     * @return array with the post info
3430
     */
3431
    public function getAttachmentList($eventId, $courseInfo)
3432
    {
3433
        $tableAttachment = Database::get_course_table(TABLE_AGENDA_ATTACHMENT);
3434
        $courseId = (int) $courseInfo['real_id'];
3435
        $eventId = (int) $eventId;
3436
3437
        $sql = "SELECT id, path, filename, comment
3438
                FROM $tableAttachment
3439
                WHERE
3440
                    c_id = $courseId AND
3441
                    agenda_id = $eventId";
3442
        $result = Database::query($sql);
3443
        $list = [];
3444
        if (Database::num_rows($result) != 0) {
3445
            $list = Database::store_result($result, 'ASSOC');
3446
        }
3447
3448
        return $list;
3449
    }
3450
3451
    /**
3452
     * Show a list with all the attachments according to the post's id.
3453
     *
3454
     * @param int   $attachmentId
3455
     * @param int   $eventId
3456
     * @param array $courseInfo
3457
     *
3458
     * @return array with the post info
3459
     */
3460
    public function getAttachment($attachmentId, $eventId, $courseInfo)
3461
    {
3462
        if (empty($courseInfo) || empty($attachmentId) || empty($eventId)) {
3463
            return [];
3464
        }
3465
3466
        $tableAttachment = Database::get_course_table(TABLE_AGENDA_ATTACHMENT);
3467
        $courseId = (int) $courseInfo['real_id'];
3468
        $eventId = (int) $eventId;
3469
        $attachmentId = (int) $attachmentId;
3470
3471
        $row = [];
3472
        $sql = "SELECT id, path, filename, comment
3473
                FROM $tableAttachment
3474
                WHERE
3475
                    c_id = $courseId AND
3476
                    agenda_id = $eventId AND
3477
                    id = $attachmentId
3478
                ";
3479
        $result = Database::query($sql);
3480
        if (Database::num_rows($result) != 0) {
3481
            $row = Database::fetch_array($result, 'ASSOC');
3482
        }
3483
3484
        return $row;
3485
    }
3486
3487
    /**
3488
     * Add an attachment file into agenda.
3489
     *
3490
     * @param int    $eventId
3491
     * @param array  $fileUserUpload ($_FILES['user_upload'])
3492
     * @param string $comment        about file
3493
     * @param array  $courseInfo
3494
     *
3495
     * @return string
3496
     */
3497
    public function addAttachment(
3498
        $eventId,
3499
        $fileUserUpload,
3500
        $comment,
3501
        $courseInfo
3502
    ) {
3503
        $agenda_table_attachment = Database::get_course_table(TABLE_AGENDA_ATTACHMENT);
3504
        $eventId = (int) $eventId;
3505
3506
        // Storing the attachments
3507
        $upload_ok = false;
3508
        if (!empty($fileUserUpload['name'])) {
3509
            $upload_ok = process_uploaded_file($fileUserUpload);
3510
        }
3511
3512
        if (!empty($upload_ok)) {
3513
            $courseDir = $courseInfo['directory'].'/upload/calendar';
3514
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
3515
            $uploadDir = $sys_course_path.$courseDir;
3516
3517
            // Try to add an extension to the file if it hasn't one
3518
            $new_file_name = add_ext_on_mime(
3519
                stripslashes($fileUserUpload['name']),
3520
                $fileUserUpload['type']
3521
            );
3522
3523
            // user's file name
3524
            $file_name = $fileUserUpload['name'];
3525
3526
            if (!filter_extension($new_file_name)) {
3527
                return Display::return_message(
3528
                    get_lang('UplUnableToSaveFileFilteredExtension'),
3529
                    'error'
3530
                );
3531
            } else {
3532
                $new_file_name = uniqid('');
3533
                $new_path = $uploadDir.'/'.$new_file_name;
3534
                $result = @move_uploaded_file(
3535
                    $fileUserUpload['tmp_name'],
3536
                    $new_path
3537
                );
3538
                $courseId = api_get_course_int_id();
3539
                $size = intval($fileUserUpload['size']);
3540
                // Storing the attachments if any
3541
                if ($result) {
3542
                    $params = [
3543
                        'c_id' => $courseId,
3544
                        'filename' => $file_name,
3545
                        'comment' => $comment,
3546
                        'path' => $new_file_name,
3547
                        'agenda_id' => $eventId,
3548
                        'size' => $size,
3549
                    ];
3550
                    $id = Database::insert($agenda_table_attachment, $params);
3551
                    if ($id) {
3552
                        $sql = "UPDATE $agenda_table_attachment
3553
                                SET id = iid WHERE iid = $id";
3554
                        Database::query($sql);
3555
3556
                        api_item_property_update(
3557
                            $courseInfo,
3558
                            'calendar_event_attachment',
3559
                            $id,
3560
                            'AgendaAttachmentAdded',
3561
                            api_get_user_id()
3562
                        );
3563
                    }
3564
                }
3565
            }
3566
        }
3567
    }
3568
3569
    /**
3570
     * @param int    $attachmentId
3571
     * @param int    $eventId
3572
     * @param array  $fileUserUpload
3573
     * @param string $comment
3574
     * @param array  $courseInfo
3575
     */
3576
    public function updateAttachment(
3577
        $attachmentId,
3578
        $eventId,
3579
        $fileUserUpload,
3580
        $comment,
3581
        $courseInfo
3582
    ) {
3583
        $attachment = $this->getAttachment(
3584
            $attachmentId,
3585
            $eventId,
3586
            $courseInfo
3587
        );
3588
        if (!empty($attachment)) {
3589
            $this->deleteAttachmentFile($attachmentId, $courseInfo);
3590
        }
3591
        $this->addAttachment($eventId, $fileUserUpload, $comment, $courseInfo);
3592
    }
3593
3594
    /**
3595
     * This function delete a attachment file by id.
3596
     *
3597
     * @param int   $attachmentId
3598
     * @param array $courseInfo
3599
     *
3600
     * @return string
3601
     */
3602
    public function deleteAttachmentFile($attachmentId, $courseInfo)
3603
    {
3604
        $table = Database::get_course_table(TABLE_AGENDA_ATTACHMENT);
3605
        $attachmentId = (int) $attachmentId;
3606
        $courseId = $courseInfo['real_id'];
3607
3608
        if (empty($courseId) || empty($attachmentId)) {
3609
            return false;
3610
        }
3611
3612
        $sql = "DELETE FROM $table
3613
                WHERE c_id = $courseId AND id = ".$attachmentId;
3614
        $result = Database::query($sql);
3615
3616
        // update item_property
3617
        api_item_property_update(
3618
            $courseInfo,
3619
            'calendar_event_attachment',
3620
            $attachmentId,
3621
            'AgendaAttachmentDeleted',
3622
            api_get_user_id()
3623
        );
3624
3625
        if (!empty($result)) {
3626
            return Display::return_message(
3627
                get_lang("AttachmentFileDeleteSuccess"),
3628
                'confirmation'
3629
            );
3630
        }
3631
    }
3632
3633
    /**
3634
     * @param int $eventId
3635
     *
3636
     * @return array
3637
     */
3638
    public function getAllRepeatEvents($eventId)
3639
    {
3640
        $events = [];
3641
        $eventId = (int) $eventId;
3642
3643
        switch ($this->type) {
3644
            case 'personal':
3645
                break;
3646
            case 'course':
3647
                if (!empty($this->course['real_id'])) {
3648
                    $sql = "SELECT * FROM ".$this->tbl_course_agenda."
3649
                            WHERE
3650
                                c_id = ".$this->course['real_id']." AND
3651
                                parent_event_id = ".$eventId;
3652
                    $result = Database::query($sql);
3653
                    if (Database::num_rows($result)) {
3654
                        while ($row = Database::fetch_array($result, 'ASSOC')) {
3655
                            $events[] = $row;
3656
                        }
3657
                    }
3658
                }
3659
                break;
3660
        }
3661
3662
        return $events;
3663
    }
3664
3665
    /**
3666
     * @param int $eventId
3667
     * @param int $courseId
3668
     *
3669
     * @return bool
3670
     */
3671
    public function hasChildren($eventId, $courseId)
3672
    {
3673
        $eventId = (int) $eventId;
3674
        $courseId = (int) $courseId;
3675
3676
        $sql = "SELECT count(DISTINCT(id)) as count
3677
                FROM ".$this->tbl_course_agenda."
3678
                WHERE
3679
                    c_id = $courseId AND
3680
                    parent_event_id = $eventId";
3681
        $result = Database::query($sql);
3682
        if (Database::num_rows($result)) {
3683
            $row = Database::fetch_array($result, 'ASSOC');
3684
3685
            return $row['count'] > 0;
3686
        }
3687
3688
        return false;
3689
    }
3690
3691
    public function displayActions(string $view, ?string $filter = ''): string
3692
    {
3693
        $groupInfo = GroupManager::get_group_properties(api_get_group_id());
3694
        $groupIid = $groupInfo['iid'] ?? 0;
3695
3696
        $codePath = api_get_path(WEB_CODE_PATH);
3697
3698
        $currentUserId = api_get_user_id();
3699
        $cidReq = api_get_cidreq();
3700
3701
        $actionsLeft = Display::url(
3702
            Display::return_icon('calendar.png', get_lang('Calendar'), [], ICON_SIZE_MEDIUM),
3703
            $codePath."calendar/agenda_js.php?type={$this->type}&$cidReq"
3704
        );
3705
        $actionsLeft .= Display::url(
3706
            Display::return_icon('week.png', get_lang('AgendaList'), [], ICON_SIZE_MEDIUM),
3707
            $codePath."calendar/agenda_list.php?type={$this->type}&$cidReq"
3708
        );
3709
3710
        $isAllowedToEdit = api_is_allowed_to_edit(false, true);
3711
3712
        $form = '';
3713
        if ($isAllowedToEdit
3714
            || ('personal' === $this->type && !api_is_anonymous() && 'true' === api_get_setting('allow_personal_agenda'))
3715
            || (
3716
                '1' === api_get_course_setting('allow_user_edit_agenda') && !api_is_anonymous() &&
3717
                api_is_allowed_to_session_edit(false, true))
3718
            || (
3719
                GroupManager::user_has_access($currentUserId, $groupIid, GroupManager::GROUP_TOOL_CALENDAR)
3720
                && GroupManager::is_tutor_of_group($currentUserId, $groupInfo)
3721
            )
3722
        ) {
3723
            $actionsLeft .= Display::url(
3724
                Display::return_icon('new_event.png', get_lang('AgendaAdd'), [], ICON_SIZE_MEDIUM),
3725
                $codePath."calendar/agenda.php?action=add&type={$this->type}&$cidReq"
3726
            );
3727
3728
            $actionsLeft .= Display::url(
3729
                Display::return_icon('import_calendar.png', get_lang('ICalFileImport'), [], ICON_SIZE_MEDIUM),
3730
                $codePath."calendar/agenda.php?action=importical&type={$this->type}&$cidReq"
3731
            );
3732
3733
            if ($this->type === 'course') {
3734
                if (!isset($_GET['action'])) {
3735
                    $form = new FormValidator(
3736
                        'form-search',
3737
                        'post',
3738
                        '',
3739
                        '',
3740
                        [],
3741
                        FormValidator::LAYOUT_INLINE
3742
                    );
3743
                    $attributes = [
3744
                        'multiple' => false,
3745
                        'id' => 'select_form_id_search',
3746
                    ];
3747
                    $selectedValues = $this->parseAgendaFilter($filter);
3748
                    $this->showToForm($form, $selectedValues, $attributes);
3749
                    $form = $form->returnForm();
3750
                }
3751
3752
                if (true === api_get_configuration_value('agenda_reminders') && $isAllowedToEdit) {
3753
                    $actionsLeft .= Display::url(
3754
                        Display::return_icon(
3755
                            'course_request_pending.png',
3756
                            get_lang('ImportCourseEvents'),
3757
                            [],
3758
                            ICON_SIZE_MEDIUM
3759
                        ),
3760
                        $codePath."calendar/agenda.php?action=import_course_agenda_reminders&type={$this->type}&$cidReq"
3761
                    );
3762
                }
3763
            }
3764
        }
3765
3766
        if ($this->type === 'personal' && !api_is_anonymous()) {
3767
            $actionsLeft .= Display::url(
3768
                Display::return_icon('1day.png', get_lang('SessionsPlanCalendar'), [], ICON_SIZE_MEDIUM),
3769
                $codePath.'calendar/planification.php'
3770
            );
3771
3772
            if (api_is_student_boss() || api_is_platform_admin()) {
3773
                $actionsLeft .= Display::url(
3774
                    Display::return_icon('calendar-user.png', get_lang('MyStudentsSchedule'), [], ICON_SIZE_MEDIUM),
3775
                    $codePath.'mySpace/calendar_plan.php'
3776
                );
3777
            }
3778
        }
3779
3780
        if (api_is_platform_admin()
3781
            || api_is_teacher()
3782
            || api_is_student_boss()
3783
            || api_is_drh()
3784
            || api_is_session_admin()
3785
            || api_is_coach()
3786
        ) {
3787
            if ($this->type == 'personal') {
3788
                $form = '';
3789
                if (!isset($_GET['action'])) {
3790
                    $form = new FormValidator(
3791
                        'form-search',
3792
                        'get',
3793
                        api_get_self().'?type=personal&',
3794
                        '',
3795
                        [],
3796
                        FormValidator::LAYOUT_INLINE
3797
                    );
3798
3799
                    $sessions = [];
3800
3801
                    if (api_is_drh()) {
3802
                        $sessionList = SessionManager::get_sessions_followed_by_drh($currentUserId);
3803
                        if (!empty($sessionList)) {
3804
                            foreach ($sessionList as $sessionItem) {
3805
                                $sessions[$sessionItem['id']] = strip_tags($sessionItem['name']);
3806
                            }
3807
                        }
3808
                    } else {
3809
                        $sessions = SessionManager::get_sessions_by_user($currentUserId);
3810
                        $sessions = array_column($sessions, 'session_name', 'session_id');
3811
                    }
3812
3813
                    $form->addHidden('type', 'personal');
3814
                    $sessions = ['0' => get_lang('SelectAnOption')] + $sessions;
3815
3816
                    $form->addSelect(
3817
                        'session_id',
3818
                        get_lang('Session'),
3819
                        $sessions,
3820
                        ['id' => 'session_id', 'onchange' => 'submit();']
3821
                    );
3822
3823
                    $form->addButton('reset', get_lang('Reset'), 'eraser');
3824
                    $form = $form->returnForm();
3825
                }
3826
            }
3827
        }
3828
3829
        $actionsRight = '';
3830
        if ($view == 'calendar') {
3831
            $actionsRight .= $form;
3832
        }
3833
3834
        return Display::toolbarAction(
3835
            'toolbar-agenda',
3836
            [$actionsLeft, $actionsRight]
3837
        );
3838
    }
3839
3840
    /**
3841
     * @return FormValidator
3842
     */
3843
    public function getImportCalendarForm()
3844
    {
3845
        $form = new FormValidator(
3846
            'frm_import_ical',
3847
            'post',
3848
            api_get_self().'?action=importical&type='.$this->type,
3849
            ['enctype' => 'multipart/form-data']
3850
        );
3851
        $form->addHeader(get_lang('ICalFileImport'));
3852
        $form->addElement('file', 'ical_import', get_lang('ICalFileImport'));
3853
        $form->addRule(
3854
            'ical_import',
3855
            get_lang('ThisFieldIsRequired'),
3856
            'required'
3857
        );
3858
        $form->addButtonImport(get_lang('Import'), 'ical_submit');
3859
3860
        return $form;
3861
    }
3862
3863
    /**
3864
     * @param array $courseInfo
3865
     * @param $file
3866
     *
3867
     * @return false|string
3868
     */
3869
    public function importEventFile($courseInfo, $file)
3870
    {
3871
        $charset = api_get_system_encoding();
3872
        $filepath = api_get_path(SYS_ARCHIVE_PATH).$file['name'];
3873
        $messages = [];
3874
3875
        if (!@move_uploaded_file($file['tmp_name'], $filepath)) {
3876
            error_log(
3877
                'Problem moving uploaded file: '.$file['error'].' in '.__FILE__.' line '.__LINE__
3878
            );
3879
3880
            return false;
3881
        }
3882
3883
        $data = file_get_contents($filepath);
3884
3885
        $trans = [
3886
            'DAILY' => 'daily',
3887
            'WEEKLY' => 'weekly',
3888
            'MONTHLY' => 'monthlyByDate',
3889
            'YEARLY' => 'yearly',
3890
        ];
3891
        $sentTo = ['everyone' => true];
3892
        $calendar = Sabre\VObject\Reader::read($data);
3893
        $currentTimeZone = api_get_timezone();
3894
        if (!empty($calendar->VEVENT)) {
3895
            /** @var Sabre\VObject\Component\VEvent $event */
3896
            foreach ($calendar->VEVENT as $event) {
3897
                $tempDate = $event->DTSTART->getValue();
3898
                if ('Z' == substr($tempDate, -1) && 'UTC' != date('e', strtotime($tempDate))) {
3899
                    $event->DTSTART->setValue(gmdate('Ymd\THis\Z', strtotime($tempDate)));
3900
                }
3901
                $tempDate = $event->DTEND->getValue();
3902
                if ('Z' == substr($tempDate, -1) && 'UTC' != date('e', strtotime($tempDate))) {
3903
                    $event->DTEND->setValue(gmdate('Ymd\THis\Z', strtotime($tempDate)));
3904
                }
3905
                $start = $event->DTSTART->getDateTime();
3906
                $end = $event->DTEND->getDateTime();
3907
                //Sabre\VObject\DateTimeParser::parseDateTime(string $dt, \Sabre\VObject\DateTimeZone $tz)
3908
3909
                $startDateTime = api_get_local_time(
3910
                    $start->format('Y-m-d H:i:s'),
3911
                    $currentTimeZone,
3912
                    $start->format('e')
3913
                );
3914
                $endDateTime = api_get_local_time(
3915
                    $end->format('Y-m-d H:i'),
3916
                    $currentTimeZone,
3917
                    $end->format('e')
3918
                );
3919
                $title = api_convert_encoding(
3920
                    (string) $event->summary,
3921
                    $charset,
3922
                    'UTF-8'
3923
                );
3924
                $description = api_convert_encoding(
3925
                    (string) $event->description,
3926
                    $charset,
3927
                    'UTF-8'
3928
                );
3929
3930
                $id = $this->addEvent(
3931
                    $startDateTime,
3932
                    $endDateTime,
3933
                    'false',
3934
                    $title,
3935
                    $description,
3936
                    $sentTo
3937
                );
3938
3939
                $messages[] = " $title - ".$startDateTime." - ".$endDateTime;
3940
3941
                //$attendee = (string)$event->attendee;
3942
                /** @var Sabre\VObject\Property\ICalendar\Recur $repeat */
3943
                $repeat = $event->RRULE;
3944
                if ($id && !empty($repeat)) {
3945
                    $repeat = $repeat->getParts();
3946
                    $freq = $trans[$repeat['FREQ']];
3947
3948
                    if (isset($repeat['UNTIL']) && !empty($repeat['UNTIL'])) {
3949
                        // Check if datetime or just date (strlen == 8)
3950
                        if (strlen($repeat['UNTIL']) == 8) {
3951
                            // Fix the datetime format to avoid exception in the next step
3952
                            $repeat['UNTIL'] .= 'T000000';
3953
                        }
3954
                        $until = Sabre\VObject\DateTimeParser::parseDateTime(
3955
                            $repeat['UNTIL'],
3956
                            new DateTimeZone($currentTimeZone)
3957
                        );
3958
                        $until = $until->format('Y-m-d H:i:s');
3959
                        $this->addRepeatedItem(
3960
                            $id,
3961
                            $freq,
3962
                            $until,
3963
                            $sentTo
3964
                        );
3965
                    }
3966
3967
                    if (!empty($repeat['COUNT'])) {
3968
                        /*$count = $repeat['COUNT'];
3969
                        $interval = $repeat['INTERVAL'];
3970
                        $endDate = null;
3971
                        switch($freq) {
3972
                            case 'daily':
3973
                                $start = api_strtotime($startDateTime);
3974
                                $date = new DateTime($startDateTime);
3975
                                $days = $count * $interval;
3976
                                var_dump($days);
3977
                                $date->add(new DateInterval("P".$days."D"));
3978
                                $endDate = $date->format('Y-m-d H:i');
3979
                                //$endDate = $count *
3980
                                for ($i = 0; $i < $count; $i++) {
3981
                                    $days = 86400 * 7
3982
                                }
3983
                            }
3984
                        }*/
3985
                        //$res = agenda_add_repeat_item($courseInfo, $id, $freq, $count, $attendee);
3986
                        /*$this->addRepeatedItem(
3987
                            $id,
3988
                            $freq,
3989
                            $endDate,
3990
                            $sentTo
3991
                        );*/
3992
                    }
3993
                }
3994
            }
3995
        }
3996
3997
        if (!empty($messages)) {
3998
            $messages = implode('<br /> ', $messages);
3999
        } else {
4000
            $messages = get_lang('NoAgendaItems');
4001
        }
4002
4003
        return $messages;
4004
    }
4005
4006
    /**
4007
     * Parse filter turns USER:12 to ['users' => [12])] or G:1 ['groups' => [1]].
4008
     *
4009
     * @param int $filter
4010
     *
4011
     * @return array
4012
     */
4013
    public function parseAgendaFilter($filter)
4014
    {
4015
        $everyone = false;
4016
        $groupId = null;
4017
        $userId = null;
4018
4019
        if ($filter == 'everyone') {
4020
            $everyone = true;
4021
        } else {
4022
            if (substr($filter, 0, 1) == 'G') {
4023
                $groupId = str_replace('GROUP:', '', $filter);
4024
            } else {
4025
                $userId = str_replace('USER:', '', $filter);
4026
            }
4027
        }
4028
        if (empty($userId) && empty($groupId)) {
4029
            $everyone = true;
4030
        }
4031
4032
        return [
4033
            'everyone' => $everyone,
4034
            'users' => [$userId],
4035
            'groups' => [$groupId],
4036
        ];
4037
    }
4038
4039
    /**
4040
     *    This function retrieves all the agenda items of all the courses the user is subscribed to.
4041
     */
4042
    public static function get_myagendaitems(
4043
        $user_id,
4044
        $courses_dbs,
4045
        $month,
4046
        $year
4047
    ) {
4048
        $user_id = intval($user_id);
4049
4050
        $items = [];
4051
        $my_list = [];
4052
4053
        // get agenda-items for every course
4054
        foreach ($courses_dbs as $key => $array_course_info) {
4055
            //databases of the courses
4056
            $TABLEAGENDA = Database::get_course_table(TABLE_AGENDA);
4057
            $TABLE_ITEMPROPERTY = Database::get_course_table(
4058
                TABLE_ITEM_PROPERTY
4059
            );
4060
4061
            $group_memberships = GroupManager::get_group_ids(
4062
                $array_course_info['real_id'],
4063
                $user_id
4064
            );
4065
            $course_user_status = CourseManager::getUserInCourseStatus(
4066
                $user_id,
4067
                $array_course_info['real_id']
4068
            );
4069
            // if the user is administrator of that course we show all the agenda items
4070
            if ($course_user_status == '1') {
4071
                //echo "course admin";
4072
                $sqlquery = "SELECT DISTINCT agenda.*, ip.visibility, ip.to_group_id, ip.insert_user_id, ip.ref
4073
							FROM ".$TABLEAGENDA." agenda,
4074
								 ".$TABLE_ITEMPROPERTY." ip
4075
							WHERE agenda.id = ip.ref
4076
							AND MONTH(agenda.start_date)='".$month."'
4077
							AND YEAR(agenda.start_date)='".$year."'
4078
							AND ip.tool='".TOOL_CALENDAR_EVENT."'
4079
							AND ip.visibility='1'
4080
							GROUP BY agenda.id
4081
							ORDER BY start_date ";
4082
            } else {
4083
                // if the user is not an administrator of that course
4084
                if (is_array($group_memberships) && count(
4085
                        $group_memberships
4086
                    ) > 0
4087
                ) {
4088
                    $sqlquery = "SELECT	agenda.*, ip.visibility, ip.to_group_id, ip.insert_user_id, ip.ref
4089
								FROM ".$TABLEAGENDA." agenda,
4090
									".$TABLE_ITEMPROPERTY." ip
4091
								WHERE agenda.id = ip.ref
4092
								AND MONTH(agenda.start_date)='".$month."'
4093
								AND YEAR(agenda.start_date)='".$year."'
4094
								AND ip.tool='".TOOL_CALENDAR_EVENT."'
4095
								AND	( ip.to_user_id='".$user_id."' OR (ip.to_group_id IS NULL OR ip.to_group_id IN (0, ".implode(
4096
                            ", ",
4097
                            $group_memberships
4098
                        ).")) )
4099
								AND ip.visibility='1'
4100
								ORDER BY start_date ";
4101
                } else {
4102
                    $sqlquery = "SELECT agenda.*, ip.visibility, ip.to_group_id, ip.insert_user_id, ip.ref
4103
								FROM ".$TABLEAGENDA." agenda,
4104
									".$TABLE_ITEMPROPERTY." ip
4105
								WHERE agenda.id = ip.ref
4106
								AND MONTH(agenda.start_date)='".$month."'
4107
								AND YEAR(agenda.start_date)='".$year."'
4108
								AND ip.tool='".TOOL_CALENDAR_EVENT."'
4109
								AND ( ip.to_user_id='".$user_id."' OR ip.to_group_id='0' OR ip.to_group_id IS NULL)
4110
								AND ip.visibility='1'
4111
								ORDER BY start_date ";
4112
                }
4113
            }
4114
            $result = Database::query($sqlquery);
4115
4116
            while ($item = Database::fetch_array($result, 'ASSOC')) {
4117
                $agendaday = -1;
4118
                if (!empty($item['start_date'])) {
4119
                    $item['start_date'] = api_get_local_time(
4120
                        $item['start_date']
4121
                    );
4122
                    $item['start_date_tms'] = api_strtotime(
4123
                        $item['start_date']
4124
                    );
4125
                    $agendaday = date("j", $item['start_date_tms']);
4126
                }
4127
                if (!empty($item['end_date'])) {
4128
                    $item['end_date'] = api_get_local_time($item['end_date']);
4129
                }
4130
4131
                $url = api_get_path(
4132
                        WEB_CODE_PATH
4133
                    )."calendar/agenda.php?cidReq=".urlencode(
4134
                        $array_course_info["code"]
4135
                    )."&day=$agendaday&month=$month&year=$year#$agendaday";
4136
4137
                $item['url'] = $url;
4138
                $item['course_name'] = $array_course_info['title'];
4139
                $item['calendar_type'] = 'course';
4140
                $item['course_id'] = $array_course_info['course_id'];
4141
4142
                $my_list[$agendaday][] = $item;
4143
            }
4144
        }
4145
4146
        // sorting by hour for every day
4147
        $agendaitems = [];
4148
        foreach ($items as $agendaday => $tmpitems) {
4149
            if (!isset($agendaitems[$agendaday])) {
4150
                $agendaitems[$agendaday] = '';
4151
            }
4152
            sort($tmpitems);
4153
            foreach ($tmpitems as $val) {
4154
                $agendaitems[$agendaday] .= $val;
4155
            }
4156
        }
4157
4158
        return $my_list;
4159
    }
4160
4161
    /**
4162
     * This function retrieves one personal agenda item returns it.
4163
     *
4164
     * @param    array    The array containing existing events. We add to this array.
4165
     * @param    int        Day
4166
     * @param    int        Month
4167
     * @param    int        Year (4 digits)
4168
     * @param    int        Week number
4169
     * @param    string    Type of view (month_view, week_view, day_view)
4170
     *
4171
     * @return array The results of the database query, or null if not found
4172
     */
4173
    public static function get_global_agenda_items(
4174
        $agendaitems,
4175
        $day,
4176
        $month,
4177
        $year,
4178
        $week,
4179
        $type
4180
    ) {
4181
        $tbl_global_agenda = Database::get_main_table(
4182
            TABLE_MAIN_SYSTEM_CALENDAR
4183
        );
4184
        $month = intval($month);
4185
        $year = intval($year);
4186
        $week = intval($week);
4187
        $day = intval($day);
4188
        // 1. creating the SQL statement for getting the personal agenda items in MONTH view
4189
4190
        $current_access_url_id = api_get_current_access_url_id();
4191
4192
        if ($type == "month_view" || $type == "") {
4193
            // We are in month view
4194
            $sql = "SELECT * FROM ".$tbl_global_agenda."
4195
                    WHERE
4196
                        MONTH(start_date) = ".$month." AND
4197
                        YEAR(start_date) = ".$year."  AND
4198
                        access_url_id = $current_access_url_id
4199
                    ORDER BY start_date ASC";
4200
        }
4201
        // 2. creating the SQL statement for getting the personal agenda items in WEEK view
4202
        if ($type == "week_view") { // we are in week view
4203
            $start_end_day_of_week = self::calculate_start_end_of_week(
4204
                $week,
4205
                $year
4206
            );
4207
            $start_day = $start_end_day_of_week['start']['day'];
4208
            $start_month = $start_end_day_of_week['start']['month'];
4209
            $start_year = $start_end_day_of_week['start']['year'];
4210
            $end_day = $start_end_day_of_week['end']['day'];
4211
            $end_month = $start_end_day_of_week['end']['month'];
4212
            $end_year = $start_end_day_of_week['end']['year'];
4213
            // in sql statements you have to use year-month-day for date calculations
4214
            $start_filter = $start_year."-".$start_month."-".$start_day." 00:00:00";
4215
            $start_filter = api_get_utc_datetime($start_filter);
4216
4217
            $end_filter = $end_year."-".$end_month."-".$end_day." 23:59:59";
4218
            $end_filter = api_get_utc_datetime($end_filter);
4219
            $sql = " SELECT * FROM ".$tbl_global_agenda." WHERE start_date>='".$start_filter."' AND start_date<='".$end_filter."' AND  access_url_id = $current_access_url_id ";
4220
        }
4221
        // 3. creating the SQL statement for getting the personal agenda items in DAY view
4222
        if ($type == "day_view") { // we are in day view
4223
            // we could use mysql date() function but this is only available from 4.1 and higher
4224
            $start_filter = $year."-".$month."-".$day." 00:00:00";
4225
            $start_filter = api_get_utc_datetime($start_filter);
4226
4227
            $end_filter = $year."-".$month."-".$day." 23:59:59";
4228
            $end_filter = api_get_utc_datetime($end_filter);
4229
            $sql = " SELECT * FROM ".$tbl_global_agenda." WHERE start_date>='".$start_filter."' AND start_date<='".$end_filter."'  AND  access_url_id = $current_access_url_id";
4230
        }
4231
4232
        $result = Database::query($sql);
4233
4234
        while ($item = Database::fetch_array($result)) {
4235
            if (!empty($item['start_date'])) {
4236
                $item['start_date'] = api_get_local_time($item['start_date']);
4237
                $item['start_date_tms'] = api_strtotime($item['start_date']);
4238
            }
4239
            if (!empty($item['end_date'])) {
4240
                $item['end_date'] = api_get_local_time($item['end_date']);
4241
            }
4242
4243
            // we break the date field in the database into a date and a time part
4244
            $agenda_db_date = explode(" ", $item['start_date']);
4245
            $date = $agenda_db_date[0];
4246
            $time = $agenda_db_date[1];
4247
            // we divide the date part into a day, a month and a year
4248
            $agendadate = explode("-", $date);
4249
            $year = intval($agendadate[0]);
4250
            $month = intval($agendadate[1]);
4251
            $day = intval($agendadate[2]);
4252
            // we divide the time part into hour, minutes, seconds
4253
            $agendatime = explode(":", $time);
4254
            $hour = $agendatime[0];
4255
            $minute = $agendatime[1];
4256
            $second = $agendatime[2];
4257
4258
            if ($type == 'month_view') {
4259
                $item['calendar_type'] = 'global';
4260
                $agendaitems[$day][] = $item;
4261
                continue;
4262
            }
4263
4264
            $start_time = api_format_date(
4265
                $item['start_date'],
4266
                TIME_NO_SEC_FORMAT
4267
            );
4268
            $end_time = '';
4269
            if (!empty($item['end_date'])) {
4270
                $end_time = ' - '.api_format_date(
4271
                        $item['end_date'],
4272
                        DATE_TIME_FORMAT_LONG
4273
                    );
4274
            }
4275
4276
            // if the student has specified a course we a add a link to that course
4277
            if ($item['course'] != "") {
4278
                $url = api_get_path(
4279
                        WEB_CODE_PATH
4280
                    )."admin/agenda.php?cidReq=".urlencode(
4281
                        $item['course']
4282
                    )."&day=$day&month=$month&year=$year#$day"; // RH  //Patrick Cool: to highlight the relevant agenda item
4283
                $course_link = "<a href=\"$url\" title=\"".$item['course']."\">".$item['course']."</a>";
4284
            } else {
4285
                $course_link = "";
4286
            }
4287
            // Creating the array that will be returned. If we have week or month view we have an array with the date as the key
4288
            // if we have a day_view we use a half hour as index => key 33 = 16h30
4289
            if ($type !== "day_view") {
4290
                // This is the array construction for the WEEK or MONTH view
4291
                //Display the Agenda global in the tab agenda (administrator)
4292
                $agendaitems[$day] .= "<i>$start_time $end_time</i>&nbsp;-&nbsp;";
4293
                $agendaitems[$day] .= "<b>".get_lang('GlobalEvent')."</b>";
4294
                $agendaitems[$day] .= "<div>".$item['title']."</div><br>";
4295
            } else {
4296
                // this is the array construction for the DAY view
4297
                $halfhour = 2 * $agendatime['0'];
4298
                if ($agendatime['1'] >= '30') {
4299
                    $halfhour = $halfhour + 1;
4300
                }
4301
                if (!is_array($agendaitems[$halfhour])) {
4302
                    $content = $agendaitems[$halfhour];
4303
                }
4304
                $agendaitems[$halfhour] = $content."<div><i>$hour:$minute</i> <b>".get_lang(
4305
                        'GlobalEvent'
4306
                    ).":  </b>".$item['title']."</div>";
4307
            }
4308
        }
4309
4310
        return $agendaitems;
4311
    }
4312
4313
    /**
4314
     * This function retrieves all the personal agenda items and add them to the agenda items found by the other
4315
     * functions.
4316
     */
4317
    public static function get_personal_agenda_items(
4318
        $user_id,
4319
        $agendaitems,
4320
        $day,
4321
        $month,
4322
        $year,
4323
        $week,
4324
        $type
4325
    ) {
4326
        $tbl_personal_agenda = Database::get_main_table(TABLE_PERSONAL_AGENDA);
4327
        $user_id = intval($user_id);
4328
4329
        // 1. creating the SQL statement for getting the personal agenda items in MONTH view
4330
        if ($type === "month_view" || $type === "") {
4331
            // we are in month view
4332
            $sql = "SELECT * FROM $tbl_personal_agenda
4333
                    WHERE
4334
                        user='".$user_id."' AND
4335
                        MONTH(date)='".$month."' AND
4336
                        YEAR(date) = '".$year."'
4337
                     ORDER BY date ASC";
4338
        }
4339
4340
        // 2. creating the SQL statement for getting the personal agenda items in WEEK view
4341
        // we are in week view
4342
        if ($type == "week_view") {
4343
            $start_end_day_of_week = self::calculate_start_end_of_week(
4344
                $week,
4345
                $year
4346
            );
4347
            $start_day = $start_end_day_of_week['start']['day'];
4348
            $start_month = $start_end_day_of_week['start']['month'];
4349
            $start_year = $start_end_day_of_week['start']['year'];
4350
            $end_day = $start_end_day_of_week['end']['day'];
4351
            $end_month = $start_end_day_of_week['end']['month'];
4352
            $end_year = $start_end_day_of_week['end']['year'];
4353
            // in sql statements you have to use year-month-day for date calculations
4354
            $start_filter = $start_year."-".$start_month."-".$start_day." 00:00:00";
4355
            $start_filter = api_get_utc_datetime($start_filter);
4356
            $end_filter = $end_year."-".$end_month."-".$end_day." 23:59:59";
4357
            $end_filter = api_get_utc_datetime($end_filter);
4358
            $sql = " SELECT * FROM ".$tbl_personal_agenda." WHERE user='".$user_id."' AND date>='".$start_filter."' AND date<='".$end_filter."'";
4359
        }
4360
        // 3. creating the SQL statement for getting the personal agenda items in DAY view
4361
        if ($type == "day_view") {
4362
            // we are in day view
4363
            // we could use mysql date() function but this is only available from 4.1 and higher
4364
            $start_filter = $year."-".$month."-".$day." 00:00:00";
4365
            $start_filter = api_get_utc_datetime($start_filter);
4366
            $end_filter = $year."-".$month."-".$day." 23:59:59";
4367
            $end_filter = api_get_utc_datetime($end_filter);
4368
            $sql = " SELECT * FROM ".$tbl_personal_agenda." WHERE user='".$user_id."' AND date>='".$start_filter."' AND date<='".$end_filter."'";
4369
        }
4370
4371
        $result = Database::query($sql);
4372
        while ($item = Database::fetch_array($result, 'ASSOC')) {
4373
            $time_minute = api_convert_and_format_date(
4374
                $item['date'],
4375
                TIME_NO_SEC_FORMAT
4376
            );
4377
            $item['date'] = api_get_local_time($item['date']);
4378
            $item['start_date_tms'] = api_strtotime($item['date']);
4379
            $item['content'] = $item['text'];
4380
4381
            // we break the date field in the database into a date and a time part
4382
            $agenda_db_date = explode(" ", $item['date']);
4383
            $date = $agenda_db_date[0];
4384
            $time = $agenda_db_date[1];
4385
            // we divide the date part into a day, a month and a year
4386
            $agendadate = explode("-", $item['date']);
4387
            $year = intval($agendadate[0]);
4388
            $month = intval($agendadate[1]);
4389
            $day = intval($agendadate[2]);
4390
            // we divide the time part into hour, minutes, seconds
4391
            $agendatime = explode(":", $time);
4392
4393
            $hour = $agendatime[0];
4394
            $minute = $agendatime[1];
4395
            $second = $agendatime[2];
4396
4397
            if ($type == 'month_view') {
4398
                $item['calendar_type'] = 'personal';
4399
                $item['start_date'] = $item['date'];
4400
                $agendaitems[$day][] = $item;
4401
                continue;
4402
            }
4403
4404
            // if the student has specified a course we a add a link to that course
4405
            if ($item['course'] != "") {
4406
                $url = api_get_path(
4407
                        WEB_CODE_PATH
4408
                    )."calendar/agenda.php?cidReq=".urlencode(
4409
                        $item['course']
4410
                    )."&day=$day&month=$month&year=$year#$day"; // RH  //Patrick Cool: to highlight the relevant agenda item
4411
                $course_link = "<a href=\"$url\" title=\"".$item['course']."\">".$item['course']."</a>";
4412
            } else {
4413
                $course_link = "";
4414
            }
4415
            // Creating the array that will be returned. If we have week or month view we have an array with the date as the key
4416
            // if we have a day_view we use a half hour as index => key 33 = 16h30
4417
            if ($type !== "day_view") {
4418
                // This is the array construction for the WEEK or MONTH view
4419
4420
                //Display events in agenda
4421
                $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 />";
4422
            } else {
4423
                // this is the array construction for the DAY view
4424
                $halfhour = 2 * $agendatime['0'];
4425
                if ($agendatime['1'] >= '30') {
4426
                    $halfhour = $halfhour + 1;
4427
                }
4428
4429
                //Display events by list
4430
                $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>";
4431
            }
4432
        }
4433
4434
        return $agendaitems;
4435
    }
4436
4437
    /**
4438
     * Show the monthcalender of the given month.
4439
     *
4440
     * @param    array    Agendaitems
4441
     * @param    int    Month number
4442
     * @param    int    Year number
4443
     * @param    array    Array of strings containing long week day names (deprecated, you can send an empty array
4444
     *                          instead)
4445
     * @param    string    The month name
4446
     */
4447
    public static function display_mymonthcalendar(
4448
        $user_id,
4449
        $agendaitems,
4450
        $month,
4451
        $year,
4452
        $weekdaynames,
4453
        $monthName,
4454
        $show_content = true
4455
    ) {
4456
        global $DaysShort, $course_path;
4457
        //Handle leap year
4458
        $numberofdays = [
4459
            0,
4460
            31,
4461
            28,
4462
            31,
4463
            30,
4464
            31,
4465
            30,
4466
            31,
4467
            31,
4468
            30,
4469
            31,
4470
            30,
4471
            31,
4472
        ];
4473
        if (($year % 400 == 0) or ($year % 4 == 0 and $year % 100 != 0)) {
4474
            $numberofdays[2] = 29;
4475
        }
4476
        //Get the first day of the month
4477
        $dayone = getdate(mktime(0, 0, 0, $month, 1, $year));
4478
        //Start the week on monday
4479
        $startdayofweek = $dayone['wday'] != 0 ? ($dayone['wday'] - 1) : 6;
4480
        $g_cc = (isset($_GET['courseCode']) ? $_GET['courseCode'] : '');
4481
4482
        $next_month = ($month == 1 ? 12 : $month - 1);
4483
        $prev_month = ($month == 12 ? 1 : $month + 1);
4484
4485
        $next_year = ($month == 1 ? $year - 1 : $year);
4486
        $prev_year = ($month == 12 ? $year + 1 : $year);
4487
4488
        if ($show_content) {
4489
            $back_url = Display::url(
4490
                get_lang('Previous'),
4491
                api_get_self()."?coursePath=".urlencode(
4492
                    $course_path
4493
                )."&courseCode=".Security::remove_XSS(
4494
                    $g_cc
4495
                )."&action=view&view=month&month=".$next_month."&year=".$next_year
4496
            );
4497
            $next_url = Display::url(
4498
                get_lang('Next'),
4499
                api_get_self()."?coursePath=".urlencode(
4500
                    $course_path
4501
                )."&courseCode=".Security::remove_XSS(
4502
                    $g_cc
4503
                )."&action=view&view=month&month=".$prev_month."&year=".$prev_year
4504
            );
4505
        } else {
4506
            $back_url = Display::url(
4507
                get_lang('Previous'),
4508
                '',
4509
                [
4510
                    'onclick' => "load_calendar('".$user_id."','".$next_month."', '".$next_year."'); ",
4511
                    'class' => 'btn ui-button ui-widget ui-state-default',
4512
                ]
4513
            );
4514
            $next_url = Display::url(
4515
                get_lang('Next'),
4516
                '',
4517
                [
4518
                    'onclick' => "load_calendar('".$user_id."','".$prev_month."', '".$prev_year."'); ",
4519
                    'class' => 'pull-right btn ui-button ui-widget ui-state-default',
4520
                ]
4521
            );
4522
        }
4523
        $html = '';
4524
        $html .= '<div class="actions">';
4525
        $html .= '<div class="row">';
4526
        $html .= '<div class="col-md-4">'.$back_url.'</div>';
4527
        $html .= '<div class="col-md-4"><p class="agenda-title text-center">'.$monthName." ".$year.'</p></div>';
4528
        $html .= '<div class="col-md-4">'.$next_url.'</div>';
4529
        $html .= '</div>';
4530
        $html .= '</div>';
4531
        $html .= '<table id="agenda_list2" class="table table-bordered">';
4532
        $html .= '<tr>';
4533
        for ($ii = 1; $ii < 8; $ii++) {
4534
            $html .= '<td class="weekdays">'.$DaysShort[$ii % 7].'</td>';
4535
        }
4536
        $html .= '</tr>';
4537
4538
        $curday = -1;
4539
        $today = getdate();
4540
        while ($curday <= $numberofdays[$month]) {
4541
            $html .= "<tr>";
4542
            for ($ii = 0; $ii < 7; $ii++) {
4543
                if (($curday == -1) && ($ii == $startdayofweek)) {
4544
                    $curday = 1;
4545
                }
4546
                if (($curday > 0) && ($curday <= $numberofdays[$month])) {
4547
                    $bgcolor = $class = 'class="days_week"';
4548
                    $dayheader = Display::div(
4549
                        $curday,
4550
                        ['class' => 'agenda_day']
4551
                    );
4552
                    if (($curday == $today['mday']) && ($year == $today['year']) && ($month == $today['mon'])) {
4553
                        $class = "class=\"days_today\" style=\"width:10%;\"";
4554
                    }
4555
4556
                    $html .= "<td ".$class.">".$dayheader;
4557
4558
                    if (!empty($agendaitems[$curday])) {
4559
                        $items = $agendaitems[$curday];
4560
                        $items = msort($items, 'start_date_tms');
4561
4562
                        foreach ($items as $value) {
4563
                            $value['title'] = Security::remove_XSS(
4564
                                $value['title']
4565
                            );
4566
                            $start_time = api_format_date(
4567
                                $value['start_date'],
4568
                                TIME_NO_SEC_FORMAT
4569
                            );
4570
                            $end_time = '';
4571
4572
                            if (!empty($value['end_date'])) {
4573
                                $end_time = '-&nbsp;<i>'.api_format_date(
4574
                                        $value['end_date'],
4575
                                        DATE_TIME_FORMAT_LONG
4576
                                    ).'</i>';
4577
                            }
4578
                            $complete_time = '<i>'.api_format_date(
4579
                                    $value['start_date'],
4580
                                    DATE_TIME_FORMAT_LONG
4581
                                ).'</i>&nbsp;'.$end_time;
4582
                            $time = '<i>'.$start_time.'</i>';
4583
4584
                            switch ($value['calendar_type']) {
4585
                                case 'personal':
4586
                                    $bg_color = '#D0E7F4';
4587
                                    $icon = Display::return_icon(
4588
                                        'user.png',
4589
                                        get_lang('MyAgenda'),
4590
                                        [],
4591
                                        ICON_SIZE_SMALL
4592
                                    );
4593
                                    break;
4594
                                case 'global':
4595
                                    $bg_color = '#FFBC89';
4596
                                    $icon = Display::return_icon(
4597
                                        'view_remove.png',
4598
                                        get_lang('GlobalEvent'),
4599
                                        [],
4600
                                        ICON_SIZE_SMALL
4601
                                    );
4602
                                    break;
4603
                                case 'course':
4604
                                    $bg_color = '#CAFFAA';
4605
                                    $icon_name = 'course.png';
4606
                                    if (!empty($value['session_id'])) {
4607
                                        $icon_name = 'session.png';
4608
                                    }
4609
                                    if ($show_content) {
4610
                                        $icon = Display::url(
4611
                                            Display::return_icon(
4612
                                                $icon_name,
4613
                                                $value['course_name'].' '.get_lang(
4614
                                                    'Course'
4615
                                                ),
4616
                                                [],
4617
                                                ICON_SIZE_SMALL
4618
                                            ),
4619
                                            $value['url']
4620
                                        );
4621
                                    } else {
4622
                                        $icon = Display::return_icon(
4623
                                            $icon_name,
4624
                                            $value['course_name'].' '.get_lang(
4625
                                                'Course'
4626
                                            ),
4627
                                            [],
4628
                                            ICON_SIZE_SMALL
4629
                                        );
4630
                                    }
4631
                                    break;
4632
                                default:
4633
                                    break;
4634
                            }
4635
4636
                            $result = '<div class="rounded_div_agenda" style="background-color:'.$bg_color.';">';
4637
4638
                            if ($show_content) {
4639
                                //Setting a personal event to green
4640
                                $icon = Display::div(
4641
                                    $icon,
4642
                                    ['style' => 'float:right']
4643
                                );
4644
4645
                                $link = $value['calendar_type'].'_'.$value['id'].'_'.$value['course_id'].'_'.$value['session_id'];
4646
4647
                                //Link to bubble
4648
                                $url = Display::url(
4649
                                    cut($value['title'], 40),
4650
                                    '#',
4651
                                    ['id' => $link, 'class' => 'opener']
4652
                                );
4653
                                $result .= $time.' '.$icon.' '.Display::div(
4654
                                        $url
4655
                                    );
4656
4657
                                //Hidden content
4658
                                $content = Display::div(
4659
                                    $icon.Display::tag(
4660
                                        'h2',
4661
                                        $value['course_name']
4662
                                    ).'<hr />'.Display::tag(
4663
                                        'h3',
4664
                                        $value['title']
4665
                                    ).$complete_time.'<hr />'.Security::remove_XSS(
4666
                                        $value['content']
4667
                                    )
4668
                                );
4669
4670
                                //Main div
4671
                                $result .= Display::div(
4672
                                    $content,
4673
                                    [
4674
                                        'id' => 'main_'.$link,
4675
                                        'class' => 'dialog',
4676
                                        'style' => 'display:none',
4677
                                    ]
4678
                                );
4679
                                $result .= '</div>';
4680
                                $html .= $result;
4681
                            } else {
4682
                                $html .= $result .= $icon.'</div>';
4683
                            }
4684
                        }
4685
                    }
4686
                    $html .= "</td>";
4687
                    $curday++;
4688
                } else {
4689
                    $html .= "<td></td>";
4690
                }
4691
            }
4692
            $html .= "</tr>";
4693
        }
4694
        $html .= "</table>";
4695
        echo $html;
4696
    }
4697
4698
    /**
4699
     * Get personal agenda items between two dates (=all events from all registered courses).
4700
     *
4701
     * @param int $user_id user ID of the user
4702
     * @param    string    Optional start date in datetime format (if no start date is given, uses today)
4703
     * @param    string    Optional end date in datetime format (if no date is given, uses one year from now)
4704
     *
4705
     * @return array array of events ordered by start date, in
4706
     *               [0]('datestart','dateend','title'),[1]('datestart','dateend','title','link','coursetitle') format,
4707
     *               where datestart and dateend are in yyyyMMddhhmmss format
4708
     *
4709
     * @deprecated use agenda events
4710
     */
4711
    public static function get_personal_agenda_items_between_dates(
4712
        $user_id,
4713
        $date_start = '',
4714
        $date_end = ''
4715
    ) {
4716
        $items = [];
4717
        if ($user_id != strval(intval($user_id))) {
4718
            return $items;
4719
        }
4720
        if (empty($date_start)) {
4721
            $date_start = date('Y-m-d H:i:s');
4722
        }
4723
        if (empty($date_end)) {
4724
            $date_end = date(
4725
                'Y-m-d H:i:s',
4726
                mktime(0, 0, 0, date("m"), date("d"), date("Y") + 1)
4727
            );
4728
        }
4729
        $expr = '/\d{4}-\d{2}-\d{2}\ \d{2}:\d{2}:\d{2}/';
4730
        if (!preg_match($expr, $date_start)) {
4731
            return $items;
4732
        }
4733
        if (!preg_match($expr, $date_end)) {
4734
            return $items;
4735
        }
4736
4737
        // get agenda-items for every course
4738
        $courses = api_get_user_courses($user_id, false);
4739
        foreach ($courses as $id => $course) {
4740
            $c = api_get_course_info_by_id($course['real_id']);
4741
            //databases of the courses
4742
            $t_a = Database::get_course_table(TABLE_AGENDA, $course['db']);
4743
            $t_ip = Database::get_course_table(
4744
                TABLE_ITEM_PROPERTY,
4745
                $course['db']
4746
            );
4747
            // get the groups to which the user belong
4748
            $group_memberships = GroupManager::get_group_ids(
4749
                $course['db'],
4750
                $user_id
4751
            );
4752
            // if the user is administrator of that course we show all the agenda items
4753
            if ($course['status'] == '1') {
4754
                //echo "course admin";
4755
                $sqlquery = "SELECT ".
4756
                    " DISTINCT agenda.*, ip.visibility, ip.to_group_id, ip.insert_user_id, ip.ref ".
4757
                    " FROM ".$t_a." agenda, ".
4758
                    $t_ip." ip ".
4759
                    " WHERE agenda.id = ip.ref ".
4760
                    " AND agenda.start_date>='$date_start' ".
4761
                    " AND agenda.end_date<='$date_end' ".
4762
                    " AND ip.tool='".TOOL_CALENDAR_EVENT."' ".
4763
                    " AND ip.visibility='1' ".
4764
                    " GROUP BY agenda.id ".
4765
                    " ORDER BY start_date ";
4766
            } else {
4767
                // if the user is not an administrator of that course, then...
4768
                if (is_array($group_memberships) && count(
4769
                        $group_memberships
4770
                    ) > 0
4771
                ) {
4772
                    $sqlquery = "SELECT ".
4773
                        "DISTINCT agenda.*, ip.visibility, ip.to_group_id, ip.insert_user_id, ip.ref ".
4774
                        " FROM ".$t_a." agenda, ".
4775
                        $t_ip." ip ".
4776
                        " WHERE agenda.id = ip.ref ".
4777
                        " AND agenda.start_date>='$date_start' ".
4778
                        " AND agenda.end_date<='$date_end' ".
4779
                        " AND ip.tool='".TOOL_CALENDAR_EVENT."' ".
4780
                        " AND	( ip.to_user_id='".$user_id."' OR (ip.to_group_id IS NULL OR ip.to_group_id IN (0, ".implode(
4781
                            ", ",
4782
                            $group_memberships
4783
                        ).")) ) ".
4784
                        " AND ip.visibility='1' ".
4785
                        " ORDER BY start_date ";
4786
                } else {
4787
                    $sqlquery = "SELECT ".
4788
                        "DISTINCT agenda.*, ip.visibility, ip.to_group_id, ip.insert_user_id, ip.ref ".
4789
                        " FROM ".$t_a." agenda, ".
4790
                        $t_ip." ip ".
4791
                        " WHERE agenda.id = ip.ref ".
4792
                        " AND agenda.start_date>='$date_start' ".
4793
                        " AND agenda.end_date<='$date_end' ".
4794
                        " AND ip.tool='".TOOL_CALENDAR_EVENT."' ".
4795
                        " AND ( ip.to_user_id='".$user_id."' OR ip.to_group_id='0' OR ip.to_group_id IS NULL) ".
4796
                        " AND ip.visibility='1' ".
4797
                        " ORDER BY start_date ";
4798
                }
4799
            }
4800
4801
            $result = Database::query($sqlquery);
4802
            while ($item = Database::fetch_array($result)) {
4803
                $agendaday = date("j", strtotime($item['start_date']));
4804
                $month = date("n", strtotime($item['start_date']));
4805
                $year = date("Y", strtotime($item['start_date']));
4806
                $URL = api_get_path(
4807
                        WEB_PATH
4808
                    )."main/calendar/agenda.php?cidReq=".urlencode(
4809
                        $course["code"]
4810
                    )."&day=$agendaday&month=$month&year=$year#$agendaday";
4811
                list($year, $month, $day, $hour, $min, $sec) = explode(
4812
                    '[-: ]',
4813
                    $item['start_date']
4814
                );
4815
                $start_date = $year.$month.$day.$hour.$min;
4816
                list($year, $month, $day, $hour, $min, $sec) = explode(
4817
                    '[-: ]',
4818
                    $item['end_date']
4819
                );
4820
                $end_date = $year.$month.$day.$hour.$min;
4821
4822
                $items[] = [
4823
                    'datestart' => $start_date,
4824
                    'dateend' => $end_date,
4825
                    'title' => $item['title'],
4826
                    'link' => $URL,
4827
                    'coursetitle' => $c['name'],
4828
                ];
4829
            }
4830
        }
4831
4832
        return $items;
4833
    }
4834
4835
    /**
4836
     * This function calculates the startdate of the week (monday)
4837
     * and the enddate of the week (sunday)
4838
     * and returns it as an array.
4839
     */
4840
    public static function calculate_start_end_of_week($week_number, $year)
4841
    {
4842
        // determine the start and end date
4843
        // step 1: we calculate a timestamp for a day in this week
4844
        $random_day_in_week = mktime(
4845
                0,
4846
                0,
4847
                0,
4848
                1,
4849
                1,
4850
                $year
4851
            ) + ($week_number) * (7 * 24 * 60 * 60); // we calculate a random day in this week
4852
        // step 2: we which day this is (0=sunday, 1=monday, ...)
4853
        $number_day_in_week = date('w', $random_day_in_week);
4854
        // step 3: we calculate the timestamp of the monday of the week we are in
4855
        $start_timestamp = $random_day_in_week - (($number_day_in_week - 1) * 24 * 60 * 60);
4856
        // step 4: we calculate the timestamp of the sunday of the week we are in
4857
        $end_timestamp = $random_day_in_week + ((7 - $number_day_in_week + 1) * 24 * 60 * 60) - 3600;
4858
        // step 5: calculating the start_day, end_day, start_month, end_month, start_year, end_year
4859
        $start_day = date('j', $start_timestamp);
4860
        $start_month = date('n', $start_timestamp);
4861
        $start_year = date('Y', $start_timestamp);
4862
        $end_day = date('j', $end_timestamp);
4863
        $end_month = date('n', $end_timestamp);
4864
        $end_year = date('Y', $end_timestamp);
4865
        $start_end_array['start']['day'] = $start_day;
4866
        $start_end_array['start']['month'] = $start_month;
4867
        $start_end_array['start']['year'] = $start_year;
4868
        $start_end_array['end']['day'] = $end_day;
4869
        $start_end_array['end']['month'] = $end_month;
4870
        $start_end_array['end']['year'] = $end_year;
4871
4872
        return $start_end_array;
4873
    }
4874
4875
    /**
4876
     * @return bool
4877
     */
4878
    public function getIsAllowedToEdit()
4879
    {
4880
        return $this->isAllowedToEdit;
4881
    }
4882
4883
    /**
4884
     * @param bool $isAllowedToEdit
4885
     */
4886
    public function setIsAllowedToEdit($isAllowedToEdit)
4887
    {
4888
        $this->isAllowedToEdit = $isAllowedToEdit;
4889
    }
4890
4891
    /**
4892
     * Format needed for the Fullcalendar js lib.
4893
     *
4894
     * @param string $utcTime
4895
     *
4896
     * @return bool|string
4897
     */
4898
    public function formatEventDate($utcTime)
4899
    {
4900
        if ($utcTime instanceof DateTime) {
4901
            $eventDate = $utcTime;
4902
        } else {
4903
            $utcTimeZone = new DateTimeZone('UTC');
4904
            $eventDate = new DateTime($utcTime, $utcTimeZone);
4905
        }
4906
4907
        $platformTimeZone = new DateTimeZone(api_get_timezone());
4908
4909
        $eventDate->setTimezone($platformTimeZone);
4910
4911
        return $eventDate->format(DateTime::ISO8601);
4912
    }
4913
4914
    /**
4915
     * @throws \Doctrine\ORM\OptimisticLockException
4916
     * @throws \Doctrine\ORM\ORMException
4917
     * @throws \Doctrine\ORM\TransactionRequiredException
4918
     */
4919
    public static function saveCollectiveProperties(array $inviteeUserList, bool $isCollective, int $eventId)
4920
    {
4921
        if (empty($inviteeUserList)) {
4922
            return;
4923
        }
4924
4925
        $em = Database::getManager();
4926
4927
        $event = $em->find('ChamiloCoreBundle:PersonalAgenda', $eventId);
4928
4929
        $invitation = $event->getInvitation();
4930
4931
        if ($invitation instanceof AgendaEventSubscription) {
4932
            return;
4933
        }
4934
4935
        if (!$invitation) {
4936
            $invitation = new AgendaEventInvitation();
4937
            $invitation->setCreator(api_get_user_entity(api_get_user_id()));
4938
4939
            $event->setInvitation($invitation);
4940
        }
4941
4942
        $event->setCollective($isCollective);
4943
4944
        foreach ($inviteeUserList as $inviteeId) {
4945
            $userInvitee = api_get_user_entity($inviteeId);
4946
4947
            if (!$invitation->hasUserAsInvitee($userInvitee)) {
4948
                $invitee = new AgendaEventInvitee();
4949
                $invitee
4950
                    ->setUser($userInvitee)
4951
                    ->setInvitation($invitation)
4952
                ;
4953
4954
                $em->persist($invitee);
4955
            }
4956
        }
4957
4958
        $inviteesToRemove = $invitation->getInvitees()
4959
            ->filter(function (AgendaEventInvitee $invitee) use ($inviteeUserList): bool {
4960
                $userInvitee = $invitee->getUser();
4961
4962
                return !in_array($userInvitee->getUserId(), $inviteeUserList);
4963
            });
4964
4965
        foreach ($inviteesToRemove as $invitee) {
4966
            $em->remove($invitee);
4967
        }
4968
4969
        $em->flush();
4970
    }
4971
4972
    public static function getJsForReminders(string $cssSelectorBtnAdd): string
4973
    {
4974
        return '
4975
            var template = \'<div class="form-group">\' +
4976
                \'<div class="col-sm-offset-2 col-sm-3">\' +
4977
                \'<input min="0" step="1" id="notification_count[]" type="number" class=" form-control" name="notification_count[]">\' +
4978
                \'</div>\' +
4979
                \'<div class="col-sm-3">\' +
4980
                \'<select class="form-control" name="notification_period[]" id="form_notification_period[]">\' +
4981
                \'<option value="i">'.get_lang('Minutes').'</option>\' +
4982
                \'<option value="h">'.get_lang('Hours').'</option>\' +
4983
                \'<option value="d">'.get_lang('Days').'</option>\' +
4984
                \'</select>\' +
4985
                \'</div>\' +
4986
                \'<div class="col-sm-2"><p class="form-control-static">'.get_lang('Before').'</p></div>\' +
4987
                \'<div class="text-right col-sm-2">\' +
4988
                \'<button class="btn btn-default delete-notification" type="button" aria-label="'.get_lang('Delete').'"><em class="fa fa-times"></em></button>\' +
4989
                \'</div>\' +
4990
                \'</div>\';
4991
4992
            $("'.$cssSelectorBtnAdd.'").on("click", function (e) {
4993
                e.preventDefault();
4994
4995
                $(template).appendTo("#notification_list");
4996
                $("#notification_list select").selectpicker("refresh");
4997
            });
4998
4999
            $("#notification_list").on("click", ".delete-notification", function (e) {
5000
                e.preventDefault();
5001
5002
                $(this).parents(".form-group").remove();
5003
            });';
5004
    }
5005
5006
    public static function returnGoogleCalendarUrl(int $userId): ?string
5007
    {
5008
        $extraFieldInfo = UserManager::get_extra_user_data_by_field($userId, 'google_calendar_url');
5009
5010
        if (empty($extraFieldInfo) || empty($extraFieldInfo['google_calendar_url'])) {
5011
            return null;
5012
        }
5013
5014
        return $extraFieldInfo['google_calendar_url'];
5015
    }
5016
5017
    public static function returnFullCalendarExtraSettings(): ?string
5018
    {
5019
        $settings = api_get_configuration_value('fullcalendar_settings');
5020
5021
        if (empty($settings) || empty($settings['settings'])) {
5022
            return null;
5023
        }
5024
5025
        $encoded = json_encode($settings['settings']);
5026
5027
        return substr($encoded, 1, -1).',';
5028
    }
5029
5030
    public static function returnOnHoverInfo()
5031
    {
5032
        $onHoverInfo = api_get_configuration_value('agenda_on_hover_info');
5033
5034
        if (!empty($onHoverInfo)) {
5035
            return $onHoverInfo['options'];
5036
        }
5037
5038
        return [
5039
            'comment' => true,
5040
            'description' => true,
5041
        ];
5042
    }
5043
5044
    private function addCollectiveInvitationsFields(FormValidator $form, ?PersonalAgenda $personalEvent)
5045
    {
5046
        $invitees = [];
5047
        $isCollective = false;
5048
        $withInvitation = false;
5049
5050
        if ($personalEvent) {
5051
            $eventInvitation = $personalEvent->getInvitation();
5052
            $withInvitation = $eventInvitation && !($eventInvitation instanceof AgendaEventSubscription);
5053
5054
            if ($withInvitation) {
5055
                foreach ($eventInvitation->getInvitees() as $invitee) {
5056
                    $inviteeUser = $invitee->getUser();
5057
5058
                    $invitees[$inviteeUser->getId()] = $inviteeUser->getCompleteNameWithUsername();
5059
                }
5060
            }
5061
5062
            $isCollective = $personalEvent->isCollective();
5063
        }
5064
5065
        $form->addHtml(
5066
            '<div id="invitations-block" style="display: '.($withInvitation ? 'block;' : 'none;').'">'
5067
        );
5068
        $form->addHeader(get_lang('Invitations'));
5069
        $form->addSelectAjax(
5070
            'invitees',
5071
            get_lang('Invitees'),
5072
            $invitees,
5073
            [
5074
                'multiple' => 'multiple',
5075
                'url' => api_get_path(WEB_AJAX_PATH).'message.ajax.php?a=find_users',
5076
            ]
5077
        );
5078
        $form->addCheckBox('collective', '', get_lang('IsItEditableByTheInvitees'));
5079
        $form->addHtml('<hr>');
5080
        $form->addHtml('</div>');
5081
5082
        $form->setDefaults([
5083
            'invitees' => array_keys($invitees),
5084
            'collective' => $isCollective,
5085
        ]);
5086
    }
5087
5088
    private function addSubscriptionFields(FormValidator $form, ?PersonalAgenda $personalEvent)
5089
    {
5090
        $subscribers = [];
5091
        $withSubscription = false;
5092
        $maxSubscriptions = 0;
5093
        $groupId = null;
5094
5095
        if ($personalEvent) {
5096
            $eventInvitation = $personalEvent->getInvitation();
5097
            $withSubscription = $eventInvitation instanceof AgendaEventSubscription;
5098
            $maxSubscriptions = $withSubscription ? $eventInvitation->getMaxAttendees() : 0;
5099
            $groupId = $personalEvent->getSubscriptionItemId();
5100
5101
            $subscribers = self::getInviteesForPersonalEvent($personalEvent->getId(), AgendaEventSubscriber::class);
5102
            $subscribers = array_combine(
5103
                array_column($subscribers, 'id'),
5104
                array_column($subscribers, 'name')
5105
            );
5106
        }
5107
5108
        $form->addHtml(
5109
            '<div id="subscriptions-block" style="display: '.($withSubscription ? 'block;' : 'none;').'">'
5110
        );
5111
        $form->addHeader(get_lang('Subscriptions'));
5112
        $form->addSelect(
5113
            'subscription_visibility',
5114
            get_lang('AllowSubscriptions'),
5115
            [
5116
                AgendaEventSubscription::SUBSCRIPTION_NO => get_lang('No'),
5117
                AgendaEventSubscription::SUBSCRIPTION_ALL => get_lang('AllUsersOfThePlatform'),
5118
                AgendaEventSubscription::SUBSCRIPTION_CLASS => get_lang('UsersInsideClass'),
5119
            ]
5120
        );
5121
        $slctItem = $form->addSelectAjax(
5122
            'subscription_item',
5123
            get_lang('SocialGroup').' / '.get_lang('Class'),
5124
            [],
5125
            [
5126
                'url' => api_get_path(WEB_AJAX_PATH).'usergroup.ajax.php?a=get_class_by_keyword',
5127
                'disabled' => 'disabled',
5128
            ]
5129
        );
5130
5131
        $form->addNumeric(
5132
            'max_subscriptions',
5133
            ['', get_lang('MaxSubscriptionsLeaveEmptyToNotLimit')],
5134
            [
5135
                'disabled' => 'disabled',
5136
                'step' => 1,
5137
                'min' => 0,
5138
                'value' => 0,
5139
            ]
5140
        );
5141
        $form->addHtml("<script>
5142
            $(function () {
5143
                $('#add_event_subscription_visibility')
5144
                    .on('change', function () {
5145
                        $('#max_subscriptions').prop('disabled', this.value == 0);
5146
                        $('#add_event_subscription_item').prop('disabled', this.value != 2);
5147
                    })
5148
                    .trigger('change');
5149
            })
5150
            </script>
5151
        ");
5152
5153
        $form->addSelect(
5154
            'subscribers',
5155
            get_lang('Subscribers'),
5156
            $subscribers,
5157
            ['multiple' => 'multiple']
5158
        );
5159
5160
        $form->setDefaults([
5161
            'subscribers' => array_keys($subscribers),
5162
            'max_subscriptions' => $maxSubscriptions,
5163
        ]);
5164
5165
        if ($groupId) {
5166
            $objUserGroup = new UserGroup();
5167
5168
            $groupInfo = $objUserGroup->get($groupId);
5169
5170
            $slctItem->addOption($groupInfo['name'], $groupId);
5171
        }
5172
5173
        $form->addHtml('</div>');
5174
    }
5175
5176
    private function editReminders(int $eventId, array $reminderList = [])
5177
    {
5178
        if (false === api_get_configuration_value('agenda_reminders')) {
5179
            return;
5180
        }
5181
5182
        $eventReminders = $this->parseEventReminders(
5183
            $this->getEventReminders($eventId)
5184
        );
5185
        $eventIntervalList = array_column($eventReminders, 'date_interval');
5186
5187
        foreach ($eventIntervalList as $eventIntervalInfo) {
5188
            if (!in_array($eventIntervalInfo, $reminderList)) {
5189
                $this->removeReminders($eventId, $eventIntervalInfo[0], $eventIntervalInfo[1]);
5190
            }
5191
        }
5192
5193
        foreach ($reminderList as $reminderInfo) {
5194
            if (!in_array($reminderInfo, $eventIntervalList)) {
5195
                $this->addReminder($eventId, $reminderInfo[0], $reminderInfo[1]);
5196
            }
5197
        }
5198
    }
5199
5200
    private static function isUserInvitedInEvent(int $id, int $userId): bool
5201
    {
5202
        $user = api_get_user_entity($userId);
5203
5204
        $event = Database::getManager()
5205
            ->getRepository('ChamiloCoreBundle:PersonalAgenda')
5206
            ->findOneByIdAndInvitee($id, $user)
5207
        ;
5208
5209
        return null !== $event;
5210
    }
5211
5212
    private function loadEventsAsInvitee(User $user, ?DateTime $startDate, ?DateTime $endDate)
5213
    {
5214
        $em = Database::getManager();
5215
        $eventRepo = $em->getRepository('ChamiloCoreBundle:PersonalAgenda');
5216
        $events = $eventRepo->getEventsForInvitee($user, $startDate, $endDate);
5217
5218
        foreach ($events as $event) {
5219
            $eventInfo = [];
5220
            $eventInfo['id'] = 'personal_'.$event->getId();
5221
            $eventInfo['title'] = $event->getTitle();
5222
            $eventInfo['className'] = 'personal';
5223
            $eventInfo['borderColor'] = $eventInfo['backgroundColor'] = $this->event_personal_color;
5224
            $eventInfo['editable'] = $event->isCollective();
5225
            $eventInfo['sent_to'] = get_lang('Me');
5226
            $eventInfo['type'] = 'personal';
5227
5228
            if ($event->getDate()) {
5229
                $eventInfo['start'] = $this->formatEventDate($event->getDate()->format('Y-m-d H:i:s'));
5230
                $eventInfo['start_date_localtime'] = api_get_local_time($event->getDate());
5231
            }
5232
5233
            if ($event->getEnddate()) {
5234
                $eventInfo['end'] = $this->formatEventDate($event->getEnddate()->format('Y-m-d H:i:s'));
5235
                $eventInfo['end_date_localtime'] = api_get_local_time($event->getEnddate());
5236
            }
5237
5238
            $eventInfo['description'] = $event->getText();
5239
            $eventInfo['allDay'] = $event->getAllDay();
5240
            $eventInfo['parent_event_id'] = 0;
5241
            $eventInfo['has_children'] = 0;
5242
            $eventInfo['collective'] = $event->isCollective();
5243
            $eventInfo['invitees'] = [];
5244
5245
            $invitation = $event->getInvitation();
5246
5247
            if ($invitation) {
5248
                foreach ($invitation->getInvitees() as $invitee) {
5249
                    $inviteeUser = $invitee->getUser();
5250
5251
                    if (!is_null($inviteeUser)) {
5252
                        $eventInfo['invitees'][] = [
5253
                            'id' => $inviteeUser->getId(),
5254
                            'name' => $inviteeUser->getCompleteNameWithUsername(),
5255
                        ];
5256
                    }
5257
                }
5258
            }
5259
5260
            $this->events[] = $eventInfo;
5261
        }
5262
    }
5263
5264
    /**
5265
     * @throws Exception
5266
     */
5267
    private function convertSessionWithDuration(int $userId, array $sessionInfo, DateTime $start, DateTime $end): array
5268
    {
5269
        $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser(
5270
            $sessionInfo['session_id'],
5271
            $userId
5272
        );
5273
5274
        if (empty($courseAccess)) {
5275
            throw new Exception();
5276
        }
5277
5278
        $firstAccessDate = new DateTime($courseAccess['login_course_date'], new DateTimeZone('UTC'));
5279
        $lastAccessDate = clone $firstAccessDate;
5280
        $lastAccessDate->modify('+'.$sessionInfo['duration'].' days');
5281
5282
        if ($firstAccessDate->format('Y-m-d H:i:s') > $start
5283
            && $lastAccessDate->format('Y-m-d H:i:s') < $end
5284
        ) {
5285
            throw new Exception();
5286
        }
5287
5288
        $courseList = SessionManager::get_course_list_by_session_id($sessionInfo['id']);
5289
        $firstCourse = current($courseList);
5290
5291
        return [
5292
            'id' => 'session_'.$sessionInfo['id'],
5293
            'session_id' => $sessionInfo['id'],
5294
            'title' => $sessionInfo['name'],
5295
            'description' => $sessionInfo['show_description'] ? $sessionInfo['description'] : '',
5296
            'className' => 'personal',
5297
            'borderColor' => $this->event_personal_color,
5298
            'backgroundColor' => $this->event_personal_color,
5299
            'editable' => false,
5300
            'sent_to' => get_lang('Me'),
5301
            'type' => 'session',
5302
            'start' => $firstAccessDate->format(DateTime::ISO8601),
5303
            'start_date_localtime' => api_get_local_time($firstAccessDate),
5304
            'end' => $lastAccessDate->format(DateTime::ISO8601),
5305
            'end_date_localtime' => api_get_local_time($lastAccessDate),
5306
            'allDay' => 0,
5307
            'parent_event_id' => 0,
5308
            'has_children' => 0,
5309
            'course_url' => api_get_course_url($firstCourse['code'], $sessionInfo['id']),
5310
        ];
5311
    }
5312
5313
    /**
5314
     * @throws Exception
5315
     */
5316
    private function convertSessionWithDates(array $sessionInfo, DateTime $start, DateTime $end): array
5317
    {
5318
        if ($sessionInfo['display_start_date'] < $start
5319
            && $sessionInfo['display_end_date'] > $end
5320
        ) {
5321
            throw new Exception();
5322
        }
5323
5324
        $courseList = SessionManager::get_course_list_by_session_id($sessionInfo['id']);
5325
        $firstCourse = current($courseList);
5326
5327
        return [
5328
            'id' => 'session_'.$sessionInfo['id'],
5329
            'session_id' => $sessionInfo['id'],
5330
            'title' => $sessionInfo['name'],
5331
            'description' => $sessionInfo['show_description'] ? $sessionInfo['description'] : '',
5332
            'className' => 'personal',
5333
            'borderColor' => $this->event_personal_color,
5334
            'backgroundColor' => $this->event_personal_color,
5335
            'editable' => false,
5336
            'sent_to' => get_lang('Me'),
5337
            'type' => 'session_subscription',
5338
            'start' => $sessionInfo['display_start_date'],
5339
            'start_date_localtime' => $sessionInfo['display_start_date']
5340
                ? $this->formatEventDate($sessionInfo['display_start_date'])
5341
                : '',
5342
            'end' => $sessionInfo['display_end_date'],
5343
            'end_date_localtime' => $sessionInfo['display_end_date']
5344
                ? $this->formatEventDate($sessionInfo['display_end_date'])
5345
                : '',
5346
            'allDay' => 0,
5347
            'parent_event_id' => 0,
5348
            'has_children' => 0,
5349
            'course_url' => api_get_course_url($firstCourse['code'], $sessionInfo['id']),
5350
        ];
5351
    }
5352
5353
    private function loadSessionsAsEvents(int $start, int $end)
5354
    {
5355
        if (false === api_get_configuration_value('personal_calendar_show_sessions_occupation')) {
5356
            return;
5357
        }
5358
5359
        $start = api_get_utc_datetime($start, false, true);
5360
        $end = api_get_utc_datetime($end, false, true);
5361
        $userInfo = api_get_user_info();
5362
        $sessionList = SessionManager::getSessionsFollowedByUser($userInfo['id'], $userInfo['status']);
5363
5364
        foreach ($sessionList as $sessionInfo) {
5365
            if (!empty($sessionInfo['duration'])) {
5366
                try {
5367
                    $this->events[] = $this->convertSessionWithDuration($userInfo['id'], $sessionInfo, $start, $end);
5368
                } catch (Exception $e) {
5369
                    continue;
5370
                }
5371
5372
                continue;
5373
            }
5374
5375
            if (empty($sessionInfo['display_start_date']) || empty($sessionInfo['display_end_date'])) {
5376
                continue;
5377
            }
5378
5379
            try {
5380
                $this->events[] = $this->convertSessionWithDates($sessionInfo, $start, $end);
5381
            } catch (Exception $e) {
5382
                continue;
5383
            }
5384
        }
5385
    }
5386
}
5387