Passed
Push — 1.11.x ( 930aea...109371 )
by Julito
12:53
created

ZoomPlugin::getRecordingSetting()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\Course;
6
use Chamilo\CoreBundle\Entity\Session;
7
use Chamilo\CourseBundle\Entity\CGroupInfo;
8
use Chamilo\PluginBundle\Zoom\API\JWTClient;
9
use Chamilo\PluginBundle\Zoom\API\MeetingInfoGet;
10
use Chamilo\PluginBundle\Zoom\API\MeetingRegistrant;
11
use Chamilo\PluginBundle\Zoom\API\MeetingSettings;
12
use Chamilo\PluginBundle\Zoom\API\RecordingFile;
13
use Chamilo\PluginBundle\Zoom\API\RecordingList;
14
use Chamilo\PluginBundle\Zoom\Meeting;
15
use Chamilo\PluginBundle\Zoom\MeetingActivity;
16
use Chamilo\PluginBundle\Zoom\MeetingRepository;
17
use Chamilo\PluginBundle\Zoom\Recording;
18
use Chamilo\PluginBundle\Zoom\RecordingRepository;
19
use Chamilo\PluginBundle\Zoom\Registrant;
20
use Chamilo\PluginBundle\Zoom\RegistrantRepository;
21
use Chamilo\UserBundle\Entity\User;
22
use Doctrine\ORM\EntityRepository;
23
use Doctrine\ORM\OptimisticLockException;
24
use Doctrine\ORM\Tools\SchemaTool;
25
use Doctrine\ORM\Tools\ToolsException;
26
27
/**
28
 * Class ZoomPlugin. Integrates Zoom meetings in courses.
29
 */
30
class ZoomPlugin extends Plugin
31
{
32
    public $isCoursePlugin = true;
33
34
    /**
35
     * @var JWTClient
36
     */
37
    private $jwtClient;
38
39
    const RECORDING_TYPE_CLOUD = 'cloud';
40
    const RECORDING_TYPE_LOCAL = 'local';
41
    const RECORDING_TYPE_NONE = 'none';
42
43
    /**
44
     * ZoomPlugin constructor.
45
     * {@inheritdoc}
46
     * Initializes the API JWT client and the entity repositories.
47
     */
48
    public function __construct()
49
    {
50
        parent::__construct(
51
            '0.3',
52
            'Sébastien Ducoulombier, Julio Montoya',
53
            [
54
                'tool_enable' => 'boolean',
55
                'apiKey' => 'text',
56
                'apiSecret' => 'text',
57
                'verificationToken' => 'text',
58
                'enableParticipantRegistration' => 'boolean',
59
                'enableCloudRecording' => [
60
                    'type' => 'select',
61
                    'options' => [
62
                        self::RECORDING_TYPE_CLOUD => 'Cloud',
63
                        self::RECORDING_TYPE_LOCAL => 'Local',
64
                        self::RECORDING_TYPE_NONE => get_lang('None'),
65
                    ],
66
                ],
67
                'enableGlobalConference' => 'boolean',
68
                'globalConferenceAllowRoles' => [
69
                    'type' => 'select',
70
                    'options' => [
71
                        PLATFORM_ADMIN => get_lang('Administrator'),
72
                        COURSEMANAGER => get_lang('Teacher'),
73
                        STUDENT => get_lang('Student'),
74
                        STUDENT_BOSS => get_lang('StudentBoss'),
75
                    ],
76
                    'attributes' => ['multiple' => 'multiple'],
77
                ],
78
            ]
79
        );
80
81
        $this->isAdminPlugin = true;
82
        $this->jwtClient = new JWTClient($this->get('apiKey'), $this->get('apiSecret'));
83
    }
84
85
    /**
86
     * Caches and returns an instance of this class.
87
     *
88
     * @return ZoomPlugin the instance to use
89
     */
90
    public static function create()
91
    {
92
        static $instance = null;
93
94
        return $instance ? $instance : $instance = new self();
95
    }
96
97
    /**
98
     * @return bool
99
     */
100
    public static function currentUserCanJoinGlobalMeeting()
101
    {
102
        $user = api_get_user_entity(api_get_user_id());
103
104
        if (null === $user) {
105
            return false;
106
        }
107
108
        //return 'true' === api_get_plugin_setting('zoom', 'enableGlobalConference') && api_user_is_login();
109
        return
110
            'true' === api_get_plugin_setting('zoom', 'enableGlobalConference')
111
            && in_array(
112
                (api_is_platform_admin() ? PLATFORM_ADMIN : $user->getStatus()),
113
                (array) api_get_plugin_setting('zoom', 'globalConferenceAllowRoles')
114
            );
115
    }
116
117
    /**
118
     * @return array
119
     */
120
    public function getProfileBlockItems()
121
    {
122
        $elements = $this->meetingsToWhichCurrentUserIsRegisteredComingSoon();
123
        $addMeetingLink = false;
124
        if (self::currentUserCanJoinGlobalMeeting()) {
125
            $addMeetingLink = true;
126
        }
127
128
        if ($addMeetingLink) {
129
            $elements[$this->get_lang('Meetings')] = api_get_path(WEB_PLUGIN_PATH).'zoom/meetings.php';
130
        }
131
132
        $items = [];
133
        foreach ($elements as $title => $link) {
134
            $items[] = [
135
                'class' => 'video-conference',
136
                'icon' => Display::return_icon(
137
                    'bbb.png',
138
                    get_lang('VideoConference')
139
                ),
140
                'link' => $link,
141
                'title' => $title,
142
            ];
143
        }
144
145
        return $items;
146
    }
147
148
    /**
149
     * @return array [ $title => $link ]
150
     */
151
    public function meetingsToWhichCurrentUserIsRegisteredComingSoon()
152
    {
153
        $linkTemplate = api_get_path(WEB_PLUGIN_PATH).'zoom/join_meeting.php?meetingId=%s';
154
        $user = api_get_user_entity(api_get_user_id());
155
        $meetings = self::getRegistrantRepository()->meetingsComingSoonRegistrationsForUser($user);
156
        $items = [];
157
        foreach ($meetings as $registrant) {
158
            $meeting = $registrant->getMeeting();
159
            $items[sprintf(
160
                $this->get_lang('DateMeetingTitle'),
161
                $meeting->formattedStartTime,
162
                $meeting->getMeetingInfoGet()->topic
163
            )] = sprintf($linkTemplate, $meeting->getId());
164
        }
165
166
        return $items;
167
    }
168
169
    /**
170
     * @return RegistrantRepository|EntityRepository
171
     */
172
    public static function getRegistrantRepository()
173
    {
174
        return Database::getManager()->getRepository(Registrant::class);
175
    }
176
177
    /**
178
     * Creates this plugin's related tables in the internal database.
179
     * Installs course fields in all courses.
180
     *
181
     * @throws ToolsException
182
     */
183
    public function install()
184
    {
185
        (new SchemaTool(Database::getManager()))->createSchema(
186
            [
187
                Database::getManager()->getClassMetadata(Meeting::class),
188
                Database::getManager()->getClassMetadata(MeetingActivity::class),
189
                Database::getManager()->getClassMetadata(Recording::class),
190
                Database::getManager()->getClassMetadata(Registrant::class),
191
            ]
192
        );
193
        $this->install_course_fields_in_all_courses();
194
    }
195
196
    /**
197
     * Drops this plugins' related tables from the internal database.
198
     * Uninstalls course fields in all courses().
199
     */
200
    public function uninstall()
201
    {
202
        (new SchemaTool(Database::getManager()))->dropSchema(
203
            [
204
                Database::getManager()->getClassMetadata(Meeting::class),
205
                Database::getManager()->getClassMetadata(MeetingActivity::class),
206
                Database::getManager()->getClassMetadata(Recording::class),
207
                Database::getManager()->getClassMetadata(Registrant::class),
208
            ]
209
        );
210
        $this->uninstall_course_fields_in_all_courses();
211
    }
212
213
    /**
214
     * Generates the search form to include in the meeting list administration page.
215
     * The form has DatePickers 'start' and 'end' and Checkbox 'reloadRecordingLists'.
216
     *
217
     * @return FormValidator the form
218
     */
219
    public function getAdminSearchForm()
220
    {
221
        $form = new FormValidator('search');
222
        $form->addHeader($this->get_lang('SearchMeeting'));
223
        $form->addDatePicker('start', get_lang('StartDate'));
224
        $form->addDatePicker('end', get_lang('EndDate'));
225
        $form->addButtonSearch(get_lang('Search'));
226
        $oneMonth = new DateInterval('P1M');
227
        if ($form->validate()) {
228
            try {
229
                $start = new DateTime($form->getSubmitValue('start'));
230
            } catch (Exception $exception) {
231
                $start = new DateTime();
232
                $start->sub($oneMonth);
233
            }
234
            try {
235
                $end = new DateTime($form->getSubmitValue('end'));
236
            } catch (Exception $exception) {
237
                $end = new DateTime();
238
                $end->add($oneMonth);
239
            }
240
        } else {
241
            $start = new DateTime();
242
            $start->sub($oneMonth);
243
            $end = new DateTime();
244
            $end->add($oneMonth);
245
        }
246
        try {
247
            $form->setDefaults(
248
                [
249
                    'start' => $start->format('Y-m-d'),
250
                    'end' => $end->format('Y-m-d'),
251
                ]
252
            );
253
        } catch (Exception $exception) {
254
            error_log(join(':', [__FILE__, __LINE__, $exception]));
255
        }
256
257
        return $form;
258
    }
259
260
    /**
261
     * Generates a meeting edit form and updates the meeting on validation.
262
     *
263
     * @param Meeting $meeting the meeting
264
     *
265
     * @throws Exception
266
     *
267
     * @return FormValidator
268
     */
269
    public function getEditMeetingForm($meeting)
270
    {
271
        $meetingInfoGet = $meeting->getMeetingInfoGet();
272
        $form = new FormValidator('edit', 'post', $_SERVER['REQUEST_URI']);
273
        $form->addHeader($this->get_lang('UpdateMeeting'));
274
        $form->addText('topic', $this->get_lang('Topic'));
275
        if ($meeting->requiresDateAndDuration()) {
276
            $startTimeDatePicker = $form->addDateTimePicker('startTime', get_lang('StartTime'));
277
            $form->setRequired($startTimeDatePicker);
278
            $durationNumeric = $form->addNumeric('duration', $this->get_lang('DurationInMinutes'));
279
            $form->setRequired($durationNumeric);
280
        }
281
        $form->addTextarea('agenda', get_lang('Agenda'), ['maxlength' => 2000]);
282
        //$form->addLabel(get_lang('Password'), $meeting->getMeetingInfoGet()->password);
283
        // $form->addText('password', get_lang('Password'), false, ['maxlength' => '10']);
284
        $form->addButtonUpdate(get_lang('Update'));
285
        if ($form->validate()) {
286
            if ($meeting->requiresDateAndDuration()) {
287
                $meetingInfoGet->start_time = (new DateTime($form->getSubmitValue('startTime')))->format(
288
                    DateTimeInterface::ISO8601
289
                );
290
                $meetingInfoGet->timezone = date_default_timezone_get();
291
                $meetingInfoGet->duration = (int) $form->getSubmitValue('duration');
292
            }
293
            $meetingInfoGet->topic = $form->getSubmitValue('topic');
294
            $meetingInfoGet->agenda = $form->getSubmitValue('agenda');
295
            try {
296
                $meetingInfoGet->update();
297
                $meeting->setMeetingInfoGet($meetingInfoGet);
298
                Database::getManager()->persist($meeting);
299
                Database::getManager()->flush();
300
                Display::addFlash(
301
                    Display::return_message($this->get_lang('MeetingUpdated'), 'confirm')
302
                );
303
            } catch (Exception $exception) {
304
                Display::addFlash(
305
                    Display::return_message($exception->getMessage(), 'error')
306
                );
307
            }
308
        }
309
        $defaults = [
310
            'topic' => $meetingInfoGet->topic,
311
            'agenda' => $meetingInfoGet->agenda,
312
        ];
313
        if ($meeting->requiresDateAndDuration()) {
314
            $defaults['startTime'] = $meeting->startDateTime->format('Y-m-d H:i');
315
            $defaults['duration'] = $meetingInfoGet->duration;
316
        }
317
        $form->setDefaults($defaults);
318
319
        return $form;
320
    }
321
322
    /**
323
     * Generates a meeting delete form and deletes the meeting on validation.
324
     *
325
     * @param Meeting $meeting
326
     * @param string  $returnURL where to redirect to on successful deletion
327
     *
328
     * @throws Exception
329
     *
330
     * @return FormValidator
331
     */
332
    public function getDeleteMeetingForm($meeting, $returnURL)
333
    {
334
        $id = $meeting->getMeetingId();
335
        $form = new FormValidator('delete', 'post', api_get_self().'?meetingId='.$id);
336
        $form->addButtonDelete($this->get_lang('DeleteMeeting'));
337
        if ($form->validate()) {
338
            $this->deleteMeeting($meeting, $returnURL);
339
        }
340
341
        return $form;
342
    }
343
344
    /**
345
     * @param Meeting $meeting
346
     * @param string  $returnURL
347
     *
348
     * @return false
349
     */
350
    public function deleteMeeting($meeting, $returnURL)
351
    {
352
        if (null === $meeting) {
353
            return false;
354
        }
355
356
        $em = Database::getManager();
357
        try {
358
            // No need to delete a instant meeting.
359
            if (\Chamilo\PluginBundle\Zoom\API\Meeting::TYPE_INSTANT != $meeting->getMeetingInfoGet()->type) {
360
                $meeting->getMeetingInfoGet()->delete();
361
            }
362
363
            $em->remove($meeting);
364
            $em->flush();
365
366
            Display::addFlash(
367
                Display::return_message($this->get_lang('MeetingDeleted'), 'confirm')
368
            );
369
            api_location($returnURL);
370
        } catch (Exception $exception) {
371
            $this->handleException($exception);
372
        }
373
    }
374
375
    /**
376
     * @param Exception $exception
377
     */
378
    public function handleException($exception)
379
    {
380
        if ($exception instanceof Exception) {
0 ignored issues
show
introduced by
$exception is always a sub-type of Exception.
Loading history...
381
            $error = json_decode($exception->getMessage());
382
            $message = $exception->getMessage();
383
            if ($error->message) {
384
                $message = $error->message;
385
            }
386
            Display::addFlash(
387
                Display::return_message($message, 'error')
388
            );
389
        }
390
    }
391
392
    /**
393
     * Generates a registrant list update form listing course and session users.
394
     * Updates the list on validation.
395
     *
396
     * @param Meeting $meeting
397
     *
398
     * @throws Exception
399
     *
400
     * @return FormValidator
401
     */
402
    public function getRegisterParticipantForm($meeting)
403
    {
404
        $form = new FormValidator('register', 'post', $_SERVER['REQUEST_URI']);
405
        $userIdSelect = $form->addSelect('userIds', $this->get_lang('RegisteredUsers'));
406
        $userIdSelect->setMultiple(true);
407
        $form->addButtonSend($this->get_lang('UpdateRegisteredUserList'));
408
409
        $users = $meeting->getRegistrableUsers();
410
        foreach ($users as $user) {
411
            $userIdSelect->addOption(
412
                api_get_person_name($user->getFirstname(), $user->getLastname()),
413
                $user->getId()
414
            );
415
        }
416
417
        if ($form->validate()) {
418
            $selectedUserIds = $form->getSubmitValue('userIds');
419
            $selectedUsers = [];
420
            if (!empty($selectedUserIds)) {
421
                foreach ($users as $user) {
422
                    if (in_array($user->getId(), $selectedUserIds)) {
423
                        $selectedUsers[] = $user;
424
                    }
425
                }
426
            }
427
428
            try {
429
                $this->updateRegistrantList($meeting, $selectedUsers);
430
                Display::addFlash(
431
                    Display::return_message($this->get_lang('RegisteredUserListWasUpdated'), 'confirm')
432
                );
433
            } catch (Exception $exception) {
434
                Display::addFlash(
435
                    Display::return_message($exception->getMessage(), 'error')
436
                );
437
            }
438
        }
439
        $registeredUserIds = [];
440
        foreach ($meeting->getRegistrants() as $registrant) {
441
            $registeredUserIds[] = $registrant->getUser()->getId();
442
        }
443
        $userIdSelect->setSelected($registeredUserIds);
444
445
        return $form;
446
    }
447
448
    /**
449
     * Generates a meeting recording files management form.
450
     * Takes action on validation.
451
     *
452
     * @param Meeting $meeting
453
     *
454
     * @throws Exception
455
     *
456
     * @return FormValidator
457
     */
458
    public function getFileForm($meeting, $returnURL)
459
    {
460
        $form = new FormValidator('fileForm', 'post', $_SERVER['REQUEST_URI']);
461
        if (!$meeting->getRecordings()->isEmpty()) {
462
            $fileIdSelect = $form->addSelect('fileIds', get_lang('Files'));
463
            $fileIdSelect->setMultiple(true);
464
            $recordingList = $meeting->getRecordings();
465
            foreach ($recordingList as &$recording) {
466
                // $recording->instanceDetails = $plugin->getPastMeetingInstanceDetails($instance->uuid);
467
                $options = [];
468
                $recordings = $recording->getRecordingMeeting()->recording_files;
469
                foreach ($recordings as $file) {
470
                    $options[] = [
471
                        'text' => sprintf(
472
                            '%s.%s (%s)',
473
                            $file->recording_type,
474
                            $file->file_type,
475
                            $file->file_size
476
                        ),
477
                        'value' => $file->id,
478
                    ];
479
                }
480
                $fileIdSelect->addOptGroup(
481
                    $options,
482
                    sprintf("%s (%s)", $recording->formattedStartTime, $recording->formattedDuration)
483
                );
484
            }
485
            $actions = [];
486
            if ($meeting->isCourseMeeting()) {
487
                $actions['CreateLinkInCourse'] = $this->get_lang('CreateLinkInCourse');
488
                $actions['CopyToCourse'] = $this->get_lang('CopyToCourse');
489
            }
490
            $actions['DeleteFile'] = $this->get_lang('DeleteFile');
491
            $form->addRadio(
492
                'action',
493
                get_lang('Action'),
494
                $actions
495
            );
496
            $form->addButtonUpdate($this->get_lang('DoIt'));
497
            if ($form->validate()) {
498
                $action = $form->getSubmitValue('action');
499
                $idList = $form->getSubmitValue('fileIds');
500
501
                foreach ($recordingList as $recording) {
502
                    $recordings = $recording->getRecordingMeeting()->recording_files;
503
504
                    foreach ($recordings as $file) {
505
                        if (in_array($file->id, $idList)) {
506
                            $name = sprintf(
507
                                $this->get_lang('XRecordingOfMeetingXFromXDurationXDotX'),
508
                                $file->recording_type,
509
                                $meeting->getId(),
510
                                $recording->formattedStartTime,
511
                                $recording->formattedDuration,
512
                                $file->file_type
513
                            );
514
                            if ('CreateLinkInCourse' === $action && $meeting->isCourseMeeting()) {
515
                                try {
516
                                    $this->createLinkToFileInCourse($meeting, $file, $name);
517
                                    Display::addFlash(
518
                                        Display::return_message(
519
                                            $this->get_lang('LinkToFileWasCreatedInCourse'),
520
                                            'success'
521
                                        )
522
                                    );
523
                                } catch (Exception $exception) {
524
                                    Display::addFlash(
525
                                        Display::return_message($exception->getMessage(), 'error')
526
                                    );
527
                                }
528
                            } elseif ('CopyToCourse' === $action && $meeting->isCourseMeeting()) {
529
                                try {
530
                                    $this->copyFileToCourse($meeting, $file, $name);
531
                                    Display::addFlash(
532
                                        Display::return_message($this->get_lang('FileWasCopiedToCourse'), 'confirm')
533
                                    );
534
                                } catch (Exception $exception) {
535
                                    Display::addFlash(
536
                                        Display::return_message($exception->getMessage(), 'error')
537
                                    );
538
                                }
539
                            } elseif ('DeleteFile' === $action) {
540
                                try {
541
                                    $name = $file->recording_type;
542
                                    $file->delete();
543
                                    Display::addFlash(
544
                                        Display::return_message($this->get_lang('FileWasDeleted').': '.$name, 'confirm')
545
                                    );
546
                                } catch (Exception $exception) {
547
                                    Display::addFlash(
548
                                        Display::return_message($exception->getMessage(), 'error')
549
                                    );
550
                                }
551
                            }
552
                        }
553
                    }
554
                }
555
                api_location($returnURL);
556
            }
557
        }
558
559
        return $form;
560
    }
561
562
    /**
563
     * Adds to the meeting course documents a link to a meeting instance recording file.
564
     *
565
     * @param Meeting       $meeting
566
     * @param RecordingFile $file
567
     * @param string        $name
568
     *
569
     * @throws Exception
570
     */
571
    public function createLinkToFileInCourse($meeting, $file, $name)
572
    {
573
        $course = $meeting->getCourse();
574
        if (null === $course) {
575
            throw new Exception('This meeting is not linked to a course');
576
        }
577
        $courseInfo = api_get_course_info_by_id($course->getId());
578
        if (empty($courseInfo)) {
579
            throw new Exception('This meeting is not linked to a valid course');
580
        }
581
        $path = '/zoom_meeting_recording_file_'.$file->id.'.'.$file->file_type;
582
        $docId = DocumentManager::addCloudLink($courseInfo, $path, $file->play_url, $name);
583
        if (!$docId) {
584
            throw new Exception(get_lang(DocumentManager::cloudLinkExists($courseInfo, $path, $file->play_url) ? 'UrlAlreadyExists' : 'ErrorAddCloudLink'));
585
        }
586
    }
587
588
    /**
589
     * Copies a recording file to a meeting's course.
590
     *
591
     * @param Meeting       $meeting
592
     * @param RecordingFile $file
593
     * @param string        $name
594
     *
595
     * @throws Exception
596
     */
597
    public function copyFileToCourse($meeting, $file, $name)
598
    {
599
        $course = $meeting->getCourse();
600
        if (null === $course) {
601
            throw new Exception('This meeting is not linked to a course');
602
        }
603
        $courseInfo = api_get_course_info_by_id($course->getId());
604
        if (empty($courseInfo)) {
605
            throw new Exception('This meeting is not linked to a valid course');
606
        }
607
        $tmpFile = tmpfile();
608
        if (false === $tmpFile) {
609
            throw new Exception('tmpfile() returned false');
610
        }
611
        $curl = curl_init($file->getFullDownloadURL($this->jwtClient->token));
612
        if (false === $curl) {
613
            throw new Exception('Could not init curl: '.curl_error($curl));
614
        }
615
        if (!curl_setopt_array(
616
            $curl,
617
            [
618
                CURLOPT_FILE => $tmpFile,
619
                CURLOPT_FOLLOWLOCATION => true,
620
                CURLOPT_MAXREDIRS => 10,
621
                CURLOPT_TIMEOUT => 120,
622
            ]
623
        )) {
624
            throw new Exception("Could not set curl options: ".curl_error($curl));
625
        }
626
        if (false === curl_exec($curl)) {
627
            throw new Exception("curl_exec failed: ".curl_error($curl));
628
        }
629
630
        $sessionId = 0;
631
        $session = $meeting->getSession();
632
        if (null !== $session) {
633
            $sessionId = $session->getId();
634
        }
635
636
        $groupId = 0;
637
        $group = $meeting->getGroup();
638
        if (null !== $group) {
639
            $groupId = $group->getIid();
640
        }
641
642
        $newPath = handle_uploaded_document(
643
            $courseInfo,
644
            [
645
                'name' => $name,
646
                'tmp_name' => stream_get_meta_data($tmpFile)['uri'],
647
                'size' => filesize(stream_get_meta_data($tmpFile)['uri']),
648
                'from_file' => true,
649
                'move_file' => true,
650
                'type' => $file->file_type,
651
            ],
652
            api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document',
653
            '/',
654
            api_get_user_id(),
655
            $groupId,
656
            null,
657
            0,
658
            'overwrite',
659
            true,
660
            false,
661
            null,
662
            $sessionId,
663
            true
664
        );
665
666
        fclose($tmpFile);
667
        if (false === $newPath) {
668
            throw new Exception('Could not handle uploaded document');
669
        }
670
    }
671
672
    /**
673
     * Generates a form to fast and easily create and start an instant meeting.
674
     * On validation, create it then redirect to it and exit.
675
     *
676
     * @return FormValidator
677
     */
678
    public function getCreateInstantMeetingForm(
679
        User $user,
680
        Course $course,
681
        CGroupInfo $group = null,
682
        Session $session = null
683
    ) {
684
        $extraUrl = '';
685
        if (!empty($course)) {
686
            $extraUrl = api_get_cidreq();
687
        }
688
        $form = new FormValidator('createInstantMeetingForm', 'post', api_get_self().'?'.$extraUrl, '_blank');
689
        $form->addButton('startButton', $this->get_lang('StartInstantMeeting'), 'video-camera', 'primary');
690
        if ($form->validate()) {
691
            try {
692
                $this->startInstantMeeting($this->get_lang('InstantMeeting'), $user, $course, $group, $session);
693
            } catch (Exception $exception) {
694
                Display::addFlash(
695
                    Display::return_message($exception->getMessage(), 'error')
696
                );
697
            }
698
        }
699
700
        return $form;
701
    }
702
703
    /**
704
     * Generates a form to schedule a meeting.
705
     * On validation, creates it and redirects to its page.
706
     *
707
     * @throws Exception
708
     *
709
     * @return FormValidator
710
     */
711
    public function getScheduleMeetingForm(User $user, Course $course = null, CGroupInfo $group = null, Session $session = null)
712
    {
713
        $extraUrl = '';
714
        if (!empty($course)) {
715
            $extraUrl = api_get_cidreq();
716
        }
717
        $form = new FormValidator('scheduleMeetingForm', 'post', api_get_self().'?'.$extraUrl);
718
        $form->addHeader($this->get_lang('ScheduleAMeeting'));
719
        $startTimeDatePicker = $form->addDateTimePicker('startTime', get_lang('StartTime'));
720
        $form->setRequired($startTimeDatePicker);
721
722
        $form->addText('topic', $this->get_lang('Topic'), true);
723
        $form->addTextarea('agenda', get_lang('Agenda'), ['maxlength' => 2000]);
724
725
        $durationNumeric = $form->addNumeric('duration', $this->get_lang('DurationInMinutes'));
726
        $form->setRequired($durationNumeric);
727
728
        if (null === $course && 'true' === $this->get('enableGlobalConference')) {
729
            $options = [];
730
            $options['everyone'] = $this->get_lang('ForEveryone');
731
            $options['registered_users'] = $this->get_lang('SomeUsers');
732
            if (!empty($options)) {
733
                if (1 === count($options)) {
734
                    $form->addHidden('type', key($options));
735
                } else {
736
                    $form->addSelect('type', $this->get_lang('ConferenceType'), $options);
737
                }
738
            }
739
        } else {
740
            // To course
741
            $form->addHidden('type', 'course');
742
        }
743
744
        /*
745
       // $passwordText = $form->addText('password', get_lang('Password'), false, ['maxlength' => '10']);
746
       if (null !== $course) {
747
           $registrationOptions = [
748
               'RegisterAllCourseUsers' => $this->get_lang('RegisterAllCourseUsers'),
749
           ];
750
           $groups = GroupManager::get_groups();
751
           if (!empty($groups)) {
752
               $registrationOptions['RegisterTheseGroupMembers'] = get_lang('RegisterTheseGroupMembers');
753
           }
754
           $registrationOptions['RegisterNoUser'] = $this->get_lang('RegisterNoUser');
755
           $userRegistrationRadio = $form->addRadio(
756
               'userRegistration',
757
               $this->get_lang('UserRegistration'),
758
               $registrationOptions
759
           );
760
           $groupOptions = [];
761
           foreach ($groups as $group) {
762
               $groupOptions[$group['id']] = $group['name'];
763
           }
764
           $groupIdsSelect = $form->addSelect(
765
               'groupIds',
766
               $this->get_lang('RegisterTheseGroupMembers'),
767
               $groupOptions
768
           );
769
           $groupIdsSelect->setMultiple(true);
770
           if (!empty($groups)) {
771
               $jsCode = sprintf(
772
                   "getElementById('%s').parentNode.parentNode.parentNode.style.display = getElementById('%s').checked ? 'block' : 'none'",
773
                   $groupIdsSelect->getAttribute('id'),
774
                   $userRegistrationRadio->getelements()[1]->getAttribute('id')
775
               );
776
777
               $form->setAttribute('onchange', $jsCode);
778
           }
779
       }*/
780
781
        $form->addButtonCreate(get_lang('Save'));
782
783
        if ($form->validate()) {
784
            $type = $form->getSubmitValue('type');
785
786
            switch ($type) {
787
                case 'everyone':
788
                    $user = null;
789
                    $group = null;
790
                    $course = null;
791
                    $session = null;
792
793
                    break;
794
                case 'registered_users':
795
                    //$user = null;
796
                    $course = null;
797
                    $session = null;
798
799
                    break;
800
                case 'course':
801
                    $user = null;
802
                    //$course = null;
803
                    //$session = null;
804
805
                    break;
806
            }
807
808
            try {
809
                $newMeeting = $this->createScheduleMeeting(
810
                    $user,
811
                    $course,
812
                    $group,
813
                    $session,
814
                    new DateTime($form->getSubmitValue('startTime')),
815
                    $form->getSubmitValue('duration'),
816
                    $form->getSubmitValue('topic'),
817
                    $form->getSubmitValue('agenda'),
818
                    substr(uniqid('z', true), 0, 10)
819
                );
820
821
                Display::addFlash(
822
                    Display::return_message($this->get_lang('NewMeetingCreated'))
823
                );
824
825
                if ($newMeeting->isCourseMeeting()) {
826
                    if ('RegisterAllCourseUsers' === $form->getSubmitValue('userRegistration')) {
827
                        $this->registerAllCourseUsers($newMeeting);
828
                        Display::addFlash(
829
                            Display::return_message($this->get_lang('AllCourseUsersWereRegistered'))
830
                        );
831
                    } elseif ('RegisterTheseGroupMembers' === $form->getSubmitValue('userRegistration')) {
832
                        $userIds = [];
833
                        foreach ($form->getSubmitValue('groupIds') as $groupId) {
834
                            $userIds = array_unique(array_merge($userIds, GroupManager::get_users($groupId)));
835
                        }
836
                        $users = Database::getManager()->getRepository('ChamiloUserBundle:User')->findBy(
837
                            ['id' => $userIds]
838
                        );
839
                        $this->registerUsers($newMeeting, $users);
840
                        Display::addFlash(
841
                            Display::return_message($this->get_lang('GroupUsersWereRegistered'))
842
                        );
843
                    }
844
                }
845
                api_location('meeting.php?meetingId='.$newMeeting->getMeetingId().'&'.$extraUrl);
846
            } catch (Exception $exception) {
847
                Display::addFlash(
848
                    Display::return_message($exception->getMessage(), 'error')
849
                );
850
            }
851
        } else {
852
            $form->setDefaults(
853
                [
854
                    'duration' => 60,
855
                    'userRegistration' => 'RegisterAllCourseUsers',
856
                ]
857
            );
858
        }
859
860
        return $form;
861
    }
862
863
    /**
864
     * Return the current global meeting (create it if needed).
865
     *
866
     * @throws Exception
867
     *
868
     * @return string
869
     */
870
    public function getGlobalMeeting()
871
    {
872
        foreach ($this->getMeetingRepository()->unfinishedGlobalMeetings() as $meeting) {
873
            return $meeting;
874
        }
875
876
        return $this->createGlobalMeeting();
877
    }
878
879
    /**
880
     * @return MeetingRepository|EntityRepository
881
     */
882
    public static function getMeetingRepository()
883
    {
884
        return Database::getManager()->getRepository(Meeting::class);
885
    }
886
887
    /**
888
     * Returns the URL to enter (start or join) a meeting or null if not possible to enter the meeting,
889
     * The returned URL depends on the meeting current status (waiting, started or finished) and the current user.
890
     *
891
     * @param Meeting $meeting
892
     *
893
     * @throws OptimisticLockException
894
     * @throws Exception
895
     *
896
     * @return string|null
897
     */
898
    public function getStartOrJoinMeetingURL($meeting)
899
    {
900
        $status = $meeting->getMeetingInfoGet()->status;
901
        $userId = api_get_user_id();
902
        $currentUser = api_get_user_entity($userId);
903
        $isGlobal = 'true' === $this->get('enableGlobalConference') && $meeting->isGlobalMeeting();
904
905
        switch ($status) {
906
            case 'ended':
907
                if ($this->userIsConferenceManager($meeting)) {
908
                    return $meeting->getMeetingInfoGet()->start_url;
909
                }
910
                break;
911
            case 'waiting':
912
                // Zoom does not allow for a new meeting to be started on first participant join.
913
                // It requires the host to start the meeting first.
914
                // Therefore for global meetings we must make the first participant the host
915
                // that is use start_url rather than join_url.
916
                // the participant will not be registered and will appear as the Zoom user account owner.
917
                // For course and user meetings, only the host can start the meeting.
918
                if ($this->userIsConferenceManager($meeting)) {
919
                    return $meeting->getMeetingInfoGet()->start_url;
920
                }
921
922
                break;
923
            case 'started':
924
                // User per conference.
925
                if ($currentUser === $meeting->getUser()) {
926
                    return $meeting->getMeetingInfoGet()->join_url;
927
                }
928
929
                // The participant is not registered, he can join only the global meeting (automatic registration).
930
                if ($isGlobal) {
931
                    return $this->registerUser($meeting, $currentUser)->getCreatedRegistration()->join_url;
932
                }
933
934
                if ($meeting->isCourseMeeting()) {
935
                    if ($this->userIsCourseConferenceManager()) {
936
                        return $meeting->getMeetingInfoGet()->start_url;
937
                    }
938
939
                    $sessionId = api_get_session_id();
940
                    $courseCode = api_get_course_id();
941
942
                    if (empty($sessionId)) {
943
                        $isSubscribed = CourseManager::is_user_subscribed_in_course(
944
                            $userId,
945
                            $courseCode,
946
                            false
947
                        );
948
                    } else {
949
                        $isSubscribed = CourseManager::is_user_subscribed_in_course(
950
                            $userId,
951
                            $courseCode,
952
                            true,
953
                            $sessionId
954
                        );
955
                    }
956
957
                    if ($isSubscribed) {
958
                        if ($meeting->isCourseGroupMeeting()) {
959
                            $groupInfo = GroupManager::get_group_properties($meeting->getGroup()->getIid(), true);
960
                            $isInGroup = GroupManager::is_user_in_group($userId, $groupInfo);
961
                            if (false === $isInGroup) {
962
                                throw new Exception($this->get_lang('YouAreNotRegisteredToThisMeeting'));
963
                            }
964
                        }
965
966
                        if (\Chamilo\PluginBundle\Zoom\API\Meeting::TYPE_INSTANT == $meeting->getMeetingInfoGet()->type) {
967
                            return $meeting->getMeetingInfoGet()->join_url;
968
                        }
969
970
                        return $this->registerUser($meeting, $currentUser)->getCreatedRegistration()->join_url;
971
                    }
972
973
                    throw new Exception($this->get_lang('YouAreNotRegisteredToThisMeeting'));
974
                }
975
976
                //if ('true' === $this->get('enableParticipantRegistration')) {
977
                    //if ('true' === $this->get('enableParticipantRegistration') && $meeting->requiresRegistration()) {
978
                    // the participant must be registered
979
                    $registrant = $meeting->getRegistrant($currentUser);
980
                    if (null == $registrant) {
981
                        throw new Exception($this->get_lang('YouAreNotRegisteredToThisMeeting'));
982
                    }
983
984
                    // the participant is registered
985
                    return $registrant->getCreatedRegistration()->join_url;
986
                //}
987
                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...
988
        }
989
990
        return null;
991
    }
992
993
    /**
994
     * @param Meeting $meeting
995
     *
996
     * @return bool whether the logged-in user can manage conferences in this context, that is either
997
     *              the current course or session coach, the platform admin or the current course admin
998
     */
999
    public function userIsConferenceManager($meeting)
1000
    {
1001
        if (null === $meeting) {
1002
            return false;
1003
        }
1004
1005
        if (api_is_coach() || api_is_platform_admin()) {
1006
            return true;
1007
        }
1008
1009
        if ($meeting->isCourseMeeting() && api_get_course_id() && api_is_course_admin()) {
1010
            return true;
1011
        }
1012
1013
        return $meeting->isUserMeeting() && $meeting->getUser()->getId() == api_get_user_id();
1014
    }
1015
1016
    /**
1017
     * @return bool whether the logged-in user can manage conferences in this context, that is either
1018
     *              the current course or session coach, the platform admin or the current course admin
1019
     */
1020
    public function userIsCourseConferenceManager()
1021
    {
1022
        if (api_is_coach() || api_is_platform_admin()) {
1023
            return true;
1024
        }
1025
1026
        if (api_get_course_id() && api_is_course_admin()) {
1027
            return true;
1028
        }
1029
1030
        return false;
1031
    }
1032
1033
    /**
1034
     * Update local recording list from remote Zoom server's version.
1035
     * Kept to implement a future administration button ("import existing data from zoom server").
1036
     *
1037
     * @param DateTime $startDate
1038
     * @param DateTime $endDate
1039
     *
1040
     * @throws OptimisticLockException
1041
     * @throws Exception
1042
     */
1043
    public function reloadPeriodRecordings($startDate, $endDate)
1044
    {
1045
        $em = Database::getManager();
1046
        $recordingRepo = $this->getRecordingRepository();
1047
        $meetingRepo = $this->getMeetingRepository();
1048
        $recordings = RecordingList::loadPeriodRecordings($startDate, $endDate);
1049
1050
        foreach ($recordings as $recordingMeeting) {
1051
            $recordingEntity = $recordingRepo->findOneBy(['uuid' => $recordingMeeting->uuid]);
1052
            if (null === $recordingEntity) {
1053
                $recordingEntity = new Recording();
1054
                $meeting = $meetingRepo->findOneBy(['meetingId' => $recordingMeeting->id]);
1055
                if (null === $meeting) {
1056
                    try {
1057
                        $meetingInfoGet = MeetingInfoGet::fromId($recordingMeeting->id);
1058
                    } catch (Exception $exception) {
1059
                        $meetingInfoGet = null; // deleted meeting with recordings
1060
                    }
1061
                    if (null !== $meetingInfoGet) {
1062
                        $meeting = $this->createMeetingFromMeeting(
1063
                            (new Meeting())->setMeetingInfoGet($meetingInfoGet)
1064
                        );
1065
                        $em->persist($meeting);
1066
                    }
1067
                }
1068
                if (null !== $meeting) {
1069
                    $recordingEntity->setMeeting($meeting);
1070
                }
1071
            }
1072
            $recordingEntity->setRecordingMeeting($recordingMeeting);
1073
            $em->persist($recordingEntity);
1074
        }
1075
        $em->flush();
1076
    }
1077
1078
    /**
1079
     * @return RecordingRepository|EntityRepository
1080
     */
1081
    public static function getRecordingRepository()
1082
    {
1083
        return Database::getManager()->getRepository(Recording::class);
1084
    }
1085
1086
    public function getToolbar($returnUrl = '')
1087
    {
1088
        if (!api_is_platform_admin()) {
1089
            return '';
1090
        }
1091
1092
        $actionsLeft = '';
1093
        $back = '';
1094
        $courseId = api_get_course_id();
1095
        if (empty($courseId)) {
1096
            $actionsLeft .=
1097
                Display::url(
1098
                    Display::return_icon('bbb.png', $this->get_lang('Meetings'), null, ICON_SIZE_MEDIUM),
1099
                    api_get_path(WEB_PLUGIN_PATH).'zoom/meetings.php'
1100
                );
1101
        } else {
1102
            $actionsLeft .=
1103
                Display::url(
1104
                    Display::return_icon('bbb.png', $this->get_lang('Meetings'), null, ICON_SIZE_MEDIUM),
1105
                    api_get_path(WEB_PLUGIN_PATH).'zoom/start.php?'.api_get_cidreq()
1106
                );
1107
        }
1108
1109
        if (!empty($returnUrl)) {
1110
            $back = Display::url(
1111
                Display::return_icon('back.png', get_lang('Back'), null, ICON_SIZE_MEDIUM),
1112
                $returnUrl
1113
            );
1114
        }
1115
1116
        if (api_is_platform_admin()) {
1117
            $actionsLeft .=
1118
                Display::url(
1119
                    Display::return_icon('settings.png', get_lang('Settings'), null, ICON_SIZE_MEDIUM),
1120
                    api_get_path(WEB_CODE_PATH).'admin/configure_plugin.php?name=zoom'
1121
                ).$back;
1122
        }
1123
1124
        return Display::toolbarAction('toolbar', [$actionsLeft]);
1125
    }
1126
1127
    /**
1128
     * Updates meeting registrants list. Adds the missing registrants and removes the extra.
1129
     *
1130
     * @param Meeting $meeting
1131
     * @param User[]  $users   list of users to be registered
1132
     *
1133
     * @throws Exception
1134
     */
1135
    private function updateRegistrantList($meeting, $users)
1136
    {
1137
        $usersToAdd = [];
1138
        foreach ($users as $user) {
1139
            $found = false;
1140
            foreach ($meeting->getRegistrants() as $registrant) {
1141
                if ($registrant->getUser() === $user) {
1142
                    $found = true;
1143
                    break;
1144
                }
1145
            }
1146
            if (!$found) {
1147
                $usersToAdd[] = $user;
1148
            }
1149
        }
1150
        $registrantsToRemove = [];
1151
        foreach ($meeting->getRegistrants() as $registrant) {
1152
            $found = false;
1153
            foreach ($users as $user) {
1154
                if ($registrant->getUser() === $user) {
1155
                    $found = true;
1156
                    break;
1157
                }
1158
            }
1159
            if (!$found) {
1160
                $registrantsToRemove[] = $registrant;
1161
            }
1162
        }
1163
        $this->registerUsers($meeting, $usersToAdd);
1164
        $this->unregister($meeting, $registrantsToRemove);
1165
    }
1166
1167
    /**
1168
     * Register users to a meeting.
1169
     *
1170
     * @param Meeting $meeting
1171
     * @param User[]  $users
1172
     *
1173
     * @throws OptimisticLockException
1174
     *
1175
     * @return User[] failed registrations [ user id => errorMessage ]
1176
     */
1177
    private function registerUsers($meeting, $users)
1178
    {
1179
        $failedUsers = [];
1180
        foreach ($users as $user) {
1181
            try {
1182
                $this->registerUser($meeting, $user, false);
1183
            } catch (Exception $exception) {
1184
                $failedUsers[$user->getId()] = $exception->getMessage();
1185
            }
1186
        }
1187
        Database::getManager()->flush();
1188
1189
        return $failedUsers;
1190
    }
1191
1192
    /**
1193
     * @throws Exception
1194
     * @throws OptimisticLockException
1195
     *
1196
     * @return Registrant
1197
     */
1198
    private function registerUser(Meeting $meeting, User $user, $andFlush = true)
1199
    {
1200
        if (empty($user->getEmail())) {
1201
            throw new Exception($this->get_lang('CannotRegisterWithoutEmailAddress'));
1202
        }
1203
1204
        $meetingRegistrant = MeetingRegistrant::fromEmailAndFirstName(
1205
            $user->getEmail(),
1206
            $user->getFirstname(),
1207
            $user->getLastname()
1208
        );
1209
1210
        $registrantEntity = (new Registrant())
1211
            ->setMeeting($meeting)
1212
            ->setUser($user)
1213
            ->setMeetingRegistrant($meetingRegistrant)
1214
            ->setCreatedRegistration($meeting->getMeetingInfoGet()->addRegistrant($meetingRegistrant));
1215
        Database::getManager()->persist($registrantEntity);
1216
1217
        if ($andFlush) {
1218
            Database::getManager()->flush($registrantEntity);
1219
        }
1220
1221
        return $registrantEntity;
1222
    }
1223
1224
    /**
1225
     * Removes registrants from a meeting.
1226
     *
1227
     * @param Meeting      $meeting
1228
     * @param Registrant[] $registrants
1229
     *
1230
     * @throws Exception
1231
     */
1232
    private function unregister($meeting, $registrants)
1233
    {
1234
        $meetingRegistrants = [];
1235
        foreach ($registrants as $registrant) {
1236
            $meetingRegistrants[] = $registrant->getMeetingRegistrant();
1237
        }
1238
        $meeting->getMeetingInfoGet()->removeRegistrants($meetingRegistrants);
1239
        $em = Database::getManager();
1240
        foreach ($registrants as $registrant) {
1241
            $em->remove($registrant);
1242
        }
1243
        $em->flush();
1244
    }
1245
1246
    /**
1247
     * Starts a new instant meeting and redirects to its start url.
1248
     *
1249
     * @param string          $topic
1250
     * @param User|null       $user
1251
     * @param Course|null     $course
1252
     * @param CGroupInfo|null $group
1253
     * @param Session|null    $session
1254
     *
1255
     * @throws Exception
1256
     */
1257
    private function startInstantMeeting($topic, $user = null, $course = null, $group = null, $session = null)
1258
    {
1259
        $meetingInfoGet = MeetingInfoGet::fromTopicAndType($topic, MeetingInfoGet::TYPE_INSTANT);
1260
        //$meetingInfoGet->settings->approval_type = MeetingSettings::APPROVAL_TYPE_AUTOMATICALLY_APPROVE;
1261
        $meeting = $this->createMeetingFromMeeting(
1262
            (new Meeting())
1263
                ->setMeetingInfoGet($meetingInfoGet)
1264
                ->setUser($user)
1265
                ->setGroup($group)
1266
                ->setCourse($course)
1267
                ->setSession($session)
1268
        );
1269
        api_location($meeting->getMeetingInfoGet()->start_url);
1270
    }
1271
1272
    /**
1273
     * Creates a meeting on Zoom servers and stores it in the local database.
1274
     *
1275
     * @param Meeting $meeting a new, unsaved meeting with at least a type and a topic
1276
     *
1277
     * @throws Exception
1278
     *
1279
     * @return Meeting
1280
     */
1281
    private function createMeetingFromMeeting($meeting)
1282
    {
1283
        $currentUser = api_get_user_entity(api_get_user_id());
1284
1285
        $meeting->getMeetingInfoGet()->settings->contact_email = $currentUser->getEmail();
1286
        $meeting->getMeetingInfoGet()->settings->contact_name = $currentUser->getFullname();
1287
        $meeting->getMeetingInfoGet()->settings->auto_recording = $this->getRecordingSetting();
1288
        $meeting->getMeetingInfoGet()->settings->registrants_email_notification = false;
1289
1290
        //$meeting->getMeetingInfoGet()->host_email = $currentUser->getEmail();
1291
        //$meeting->getMeetingInfoGet()->settings->alternative_hosts = $currentUser->getEmail();
1292
1293
        // Send create to Zoom.
1294
        $meeting->setMeetingInfoGet($meeting->getMeetingInfoGet()->create());
1295
1296
        Database::getManager()->persist($meeting);
1297
        Database::getManager()->flush();
1298
1299
        return $meeting;
1300
    }
1301
1302
    public function getRecordingSetting()
1303
    {
1304
        $recording = (string) $this->get('enableCloudRecording');
1305
1306
        if (in_array($recording, [self::RECORDING_TYPE_LOCAL, self::RECORDING_TYPE_CLOUD], true)) {
1307
1308
            return $recording;
1309
        }
1310
1311
        return self::RECORDING_TYPE_NONE;
1312
    }
1313
1314
    public function hasRecordingAvailable()
1315
    {
1316
        $recording = $this->getRecordingSetting();
1317
1318
        return self::RECORDING_TYPE_NONE !== $recording;
1319
    }
1320
1321
    /**
1322
     * @throws Exception
1323
     *
1324
     * @return Meeting
1325
     */
1326
    private function createGlobalMeeting()
1327
    {
1328
        $meetingInfoGet = MeetingInfoGet::fromTopicAndType(
1329
            $this->get_lang('GlobalMeeting'),
1330
            MeetingInfoGet::TYPE_SCHEDULED
1331
        );
1332
        $meetingInfoGet->start_time = (new DateTime())->format(DateTimeInterface::ISO8601);
1333
        $meetingInfoGet->duration = 60;
1334
        $meetingInfoGet->settings->approval_type =
1335
            ('true' === $this->get('enableParticipantRegistration'))
1336
                ? MeetingSettings::APPROVAL_TYPE_AUTOMATICALLY_APPROVE
1337
                : MeetingSettings::APPROVAL_TYPE_NO_REGISTRATION_REQUIRED;
1338
        // $meetingInfoGet->settings->host_video = true;
1339
        $meetingInfoGet->settings->participant_video = true;
1340
        $meetingInfoGet->settings->join_before_host = true;
1341
        $meetingInfoGet->settings->registrants_email_notification = false;
1342
1343
        return $this->createMeetingFromMeeting((new Meeting())->setMeetingInfoGet($meetingInfoGet));
1344
    }
1345
1346
    /**
1347
     * Schedules a meeting and returns it.
1348
     * set $course, $session and $user to null in order to create a global meeting.
1349
     *
1350
     * @param DateTime $startTime meeting local start date-time (configure local timezone on your Zoom account)
1351
     * @param int      $duration  in minutes
1352
     * @param string   $topic     short title of the meeting, required
1353
     * @param string   $agenda    ordre du jour
1354
     * @param string   $password  meeting password
1355
     *
1356
     * @throws Exception
1357
     *
1358
     * @return Meeting meeting
1359
     */
1360
    private function createScheduleMeeting(
1361
        User $user = null,
1362
        Course $course = null,
1363
        CGroupInfo $group = null,
1364
        Session $session = null,
1365
        $startTime,
1366
        $duration,
1367
        $topic,
1368
        $agenda,
1369
        $password
1370
    ) {
1371
        $meetingInfoGet = MeetingInfoGet::fromTopicAndType($topic, MeetingInfoGet::TYPE_SCHEDULED);
1372
        $meetingInfoGet->duration = $duration;
1373
        $meetingInfoGet->start_time = $startTime->format(DateTimeInterface::ISO8601);
1374
        $meetingInfoGet->agenda = $agenda;
1375
        $meetingInfoGet->password = $password;
1376
        $meetingInfoGet->settings->approval_type = MeetingSettings::APPROVAL_TYPE_NO_REGISTRATION_REQUIRED;
1377
        if ('true' === $this->get('enableParticipantRegistration')) {
1378
            $meetingInfoGet->settings->approval_type = MeetingSettings::APPROVAL_TYPE_AUTOMATICALLY_APPROVE;
1379
        }
1380
1381
        return $this->createMeetingFromMeeting(
1382
            (new Meeting())
1383
                ->setMeetingInfoGet($meetingInfoGet)
1384
                ->setUser($user)
1385
                ->setCourse($course)
1386
                ->setGroup($group)
1387
                ->setSession($session)
1388
        );
1389
    }
1390
1391
    /**
1392
     * Registers all the course users to a course meeting.
1393
     *
1394
     * @param Meeting $meeting
1395
     *
1396
     * @throws OptimisticLockException
1397
     */
1398
    private function registerAllCourseUsers($meeting)
1399
    {
1400
        $this->registerUsers($meeting, $meeting->getRegistrableUsers());
1401
    }
1402
}
1403