Differences Between: [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 namespace mod_bigbluebuttonbn; 18 19 use cm_info; 20 use context; 21 use context_course; 22 use context_module; 23 use mod_bigbluebuttonbn\local\config; 24 use mod_bigbluebuttonbn\local\helpers\files; 25 use mod_bigbluebuttonbn\local\helpers\roles; 26 use mod_bigbluebuttonbn\local\proxy\bigbluebutton_proxy; 27 use moodle_url; 28 use stdClass; 29 30 /** 31 * Instance record for mod_bigbluebuttonbn. 32 * 33 * @package mod_bigbluebuttonbn 34 * @copyright 2021 Andrew Lyons <andrew@nicols.co.uk> 35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 36 */ 37 class instance { 38 39 /** @var int Defines an instance type that includes room and recordings */ 40 public const TYPE_ALL = 0; 41 42 /** @var int Defines an instance type that includes only room */ 43 public const TYPE_ROOM_ONLY = 1; 44 45 /** @var int Defines an instance type that includes only recordings */ 46 public const TYPE_RECORDING_ONLY = 2; 47 48 /** @var cm_info The cm_info object relating to the instance */ 49 protected $cm; 50 51 /** @var stdClass The course that the instance is in */ 52 protected $course; 53 54 /** @var stdClass The instance data for the instance */ 55 protected $instancedata; 56 57 /** @var context The current context */ 58 protected $context; 59 60 /** @var array The list of participants */ 61 protected $participantlist; 62 63 /** @var int The current groupid if set */ 64 protected $groupid; 65 66 /** 67 * instance constructor. 68 * 69 * @param cm_info $cm 70 * @param stdClass $course 71 * @param stdClass $instancedata 72 * @param int|null $groupid 73 */ 74 public function __construct(cm_info $cm, stdClass $course, stdClass $instancedata, ?int $groupid = null) { 75 $this->cm = $cm; 76 $this->course = $course; 77 $this->instancedata = $instancedata; 78 $this->groupid = $groupid; 79 } 80 81 /** 82 * Get a group instance of the specified instance. 83 * 84 * @param self $originalinstance 85 * @param int $groupid 86 * @return null|self 87 */ 88 public static function get_group_instance_from_instance(self $originalinstance, int $groupid): ?self { 89 return new self( 90 $originalinstance->get_cm(), 91 $originalinstance->get_course(), 92 $originalinstance->get_instance_data(), 93 $groupid 94 ); 95 } 96 97 /** 98 * Get the instance information from an instance id. 99 * 100 * @param int $instanceid The id from the bigbluebuttonbn table 101 * @return null|self 102 */ 103 public static function get_from_instanceid(int $instanceid): ?self { 104 global $DB; 105 106 $coursetable = new \core\dml\table('course', 'c', 'c'); 107 $courseselect = $coursetable->get_field_select(); 108 $coursefrom = $coursetable->get_from_sql(); 109 110 $cmtable = new \core\dml\table('course_modules', 'cm', 'cm'); 111 $cmfrom = $cmtable->get_from_sql(); 112 113 $bbbtable = new \core\dml\table('bigbluebuttonbn', 'bbb', 'b'); 114 $bbbselect = $bbbtable->get_field_select(); 115 $bbbfrom = $bbbtable->get_from_sql(); 116 117 $sql = <<<EOF 118 SELECT {$courseselect}, {$bbbselect} 119 FROM {$cmfrom} 120 INNER JOIN {$coursefrom} ON c.id = cm.course 121 INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname 122 INNER JOIN {$bbbfrom} ON cm.instance = bbb.id 123 WHERE bbb.id = :instanceid 124 EOF; 125 126 $result = $DB->get_record_sql($sql, [ 127 'modname' => 'bigbluebuttonbn', 128 'instanceid' => $instanceid, 129 ]); 130 131 if (empty($result)) { 132 return null; 133 } 134 135 $course = $coursetable->extract_from_result($result); 136 $instancedata = $bbbtable->extract_from_result($result); 137 $cm = get_fast_modinfo($course)->instances['bigbluebuttonbn'][$instancedata->id]; 138 139 return new self($cm, $course, $instancedata); 140 } 141 142 /** 143 * Get the instance information from a cmid. 144 * 145 * @param int $cmid 146 * @return null|self 147 */ 148 public static function get_from_cmid(int $cmid): ?self { 149 global $DB; 150 151 $coursetable = new \core\dml\table('course', 'c', 'c'); 152 $courseselect = $coursetable->get_field_select(); 153 $coursefrom = $coursetable->get_from_sql(); 154 155 $cmtable = new \core\dml\table('course_modules', 'cm', 'cm'); 156 $cmfrom = $cmtable->get_from_sql(); 157 158 $bbbtable = new \core\dml\table('bigbluebuttonbn', 'bbb', 'b'); 159 $bbbselect = $bbbtable->get_field_select(); 160 $bbbfrom = $bbbtable->get_from_sql(); 161 162 $sql = <<<EOF 163 SELECT {$courseselect}, {$bbbselect} 164 FROM {$cmfrom} 165 INNER JOIN {$coursefrom} ON c.id = cm.course 166 INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname 167 INNER JOIN {$bbbfrom} ON cm.instance = bbb.id 168 WHERE cm.id = :cmid 169 EOF; 170 171 $result = $DB->get_record_sql($sql, [ 172 'modname' => 'bigbluebuttonbn', 173 'cmid' => $cmid, 174 ]); 175 176 if (empty($result)) { 177 return null; 178 } 179 180 $course = $coursetable->extract_from_result($result); 181 $instancedata = $bbbtable->extract_from_result($result); 182 $cm = get_fast_modinfo($course)->get_cm($cmid); 183 184 return new self($cm, $course, $instancedata); 185 } 186 187 /** 188 * Get the instance information from a meetingid. 189 * 190 * If a group is specified in the meetingid then this will also be set. 191 * 192 * @param string $meetingid 193 * @return null|self 194 */ 195 public static function get_from_meetingid(string $meetingid): ?self { 196 $matches = self::parse_meetingid($meetingid); 197 198 $instance = self::get_from_instanceid($matches['instanceid']); 199 200 if ($instance && array_key_exists('groupid', $matches)) { 201 $instance->set_group_id($matches['groupid']); 202 } 203 204 return $instance; 205 } 206 207 /** 208 * Parse a meetingID for key data. 209 * 210 * @param string $meetingid 211 * @return array 212 * @throws \moodle_exception 213 */ 214 public static function parse_meetingid(string $meetingid): array { 215 $result = preg_match( 216 '@(?P<meetingid>[^-]*)-(?P<courseid>[^-]*)-(?P<instanceid>\d+)(\[(?P<groupid>\d*)\])?@', 217 $meetingid, 218 $matches 219 ); 220 221 if ($result !== 1) { 222 throw new \moodle_exception("The supplied meeting id '{$meetingid}' is invalid found."); 223 } 224 225 return $matches; 226 } 227 228 /** 229 * Get all instances in the specified course. 230 * 231 * @param int $courseid 232 * @return self[] 233 */ 234 public static function get_all_instances_in_course(int $courseid): array { 235 global $DB; 236 237 $coursetable = new \core\dml\table('course', 'c', 'c'); 238 $courseselect = $coursetable->get_field_select(); 239 $coursefrom = $coursetable->get_from_sql(); 240 241 $cmtable = new \core\dml\table('course_modules', 'cm', 'cm'); 242 $cmfrom = $cmtable->get_from_sql(); 243 244 $bbbtable = new \core\dml\table('bigbluebuttonbn', 'bbb', 'b'); 245 $bbbselect = $bbbtable->get_field_select(); 246 $bbbfrom = $bbbtable->get_from_sql(); 247 248 $sql = <<<EOF 249 SELECT cm.id as cmid, {$courseselect}, {$bbbselect} 250 FROM {$cmfrom} 251 INNER JOIN {$coursefrom} ON c.id = cm.course 252 INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname 253 INNER JOIN {$bbbfrom} ON cm.instance = bbb.id 254 WHERE cm.course = :courseid 255 EOF; 256 257 $results = $DB->get_records_sql($sql, [ 258 'modname' => 'bigbluebuttonbn', 259 'courseid' => $courseid, 260 ]); 261 262 $instances = []; 263 foreach ($results as $result) { 264 $course = $coursetable->extract_from_result($result); 265 $instancedata = $bbbtable->extract_from_result($result); 266 $cm = get_fast_modinfo($course)->get_cm($result->cmid); 267 $instances[$cm->id] = new self($cm, $course, $instancedata); 268 } 269 270 return $instances; 271 } 272 273 /** 274 * Set the current group id of the activity. 275 * 276 * @param int $groupid 277 */ 278 public function set_group_id(int $groupid): void { 279 $this->groupid = $groupid; 280 } 281 282 /** 283 * Get the current groupid if set. 284 * 285 * @return int 286 */ 287 public function get_group_id(): int { 288 return empty($this->groupid) ? 0 : $this->groupid; 289 } 290 291 /** 292 * Check whether this instance is configured to use a group. 293 * 294 * @return bool 295 */ 296 public function uses_groups(): bool { 297 $groupmode = groups_get_activity_groupmode($this->get_cm()); 298 return $groupmode != NOGROUPS; 299 } 300 301 /** 302 * Get the group name for the current group, if a group has been set. 303 * 304 * @return null|string 305 */ 306 public function get_group_name(): ?string { 307 $groupid = $this->get_group_id(); 308 309 if (!$this->uses_groups()) { 310 return null; 311 } 312 313 if ($groupid == 0) { 314 return get_string('allparticipants'); 315 } 316 317 return format_string(groups_get_group_name($groupid), true, ['context' => $this->get_context()]); 318 } 319 320 /** 321 * Get the course object for the instance. 322 * 323 * @return stdClass 324 */ 325 public function get_course(): stdClass { 326 return $this->course; 327 } 328 329 /** 330 * Get the course id of the course that the instance is in. 331 * 332 * @return int 333 */ 334 public function get_course_id(): int { 335 return $this->course->id; 336 } 337 338 /** 339 * Get the cm_info object for the instance. 340 * 341 * @return cm_info 342 */ 343 public function get_cm(): cm_info { 344 return $this->cm; 345 } 346 347 /** 348 * Get the id of the course module. 349 * 350 * @return int 351 */ 352 public function get_cm_id(): int { 353 return $this->get_cm()->id; 354 } 355 356 /** 357 * Get the context. 358 * 359 * @return context_module 360 */ 361 public function get_context(): context_module { 362 if ($this->context === null) { 363 $this->context = context_module::instance($this->get_cm()->id); 364 } 365 366 return $this->context; 367 } 368 369 /** 370 * Get the context ID of the module context. 371 * 372 * @return int 373 */ 374 public function get_context_id(): int { 375 return $this->get_context()->id; 376 } 377 378 /** 379 * Get the course context. 380 * 381 * @return context_course 382 */ 383 public function get_course_context(): context_course { 384 return $this->get_context()->get_course_context(); 385 } 386 387 /** 388 * Get the big blue button instance data. 389 * 390 * @return stdClass 391 */ 392 public function get_instance_data(): stdClass { 393 return $this->instancedata; 394 } 395 396 /** 397 * Get the instance id. 398 * 399 * @return int 400 */ 401 public function get_instance_id(): int { 402 return $this->instancedata->id; 403 } 404 405 /** 406 * Helper to get an instance var. 407 * 408 * @param string $name 409 * @return mixed|null 410 */ 411 public function get_instance_var(string $name) { 412 $instance = $this->get_instance_data(); 413 if (property_exists($instance, $name)) { 414 return $instance->{$name}; 415 } 416 417 return null; 418 } 419 420 /** 421 * Get the meeting id for this meeting. 422 * 423 * @param null|int $groupid 424 * @return string 425 */ 426 public function get_meeting_id(?int $groupid = null): string { 427 $baseid = sprintf( 428 '%s-%s-%s', 429 $this->get_instance_var('meetingid'), 430 $this->get_course_id(), 431 $this->get_instance_var('id') 432 ); 433 434 if ($groupid === null) { 435 $groupid = $this->get_group_id(); 436 } 437 438 return sprintf('%s[%s]', $baseid, $groupid); 439 } 440 441 /** 442 * Get the name of the meeting, considering any group if set. 443 * 444 * @return string 445 */ 446 public function get_meeting_name(): string { 447 $meetingname = $this->get_instance_var('name'); 448 449 $groupname = $this->get_group_name(); 450 if ($groupname !== null) { 451 $meetingname .= " ({$groupname})"; 452 } 453 454 return $meetingname; 455 } 456 457 /** 458 * Get the meeting description with the pluginfile URLs optionally rewritten. 459 * 460 * @param bool $rewritepluginfileurls 461 * @return string 462 */ 463 public function get_meeting_description(bool $rewritepluginfileurls = false): string { 464 $description = $this->get_instance_var('intro'); 465 466 if ($rewritepluginfileurls) { 467 $description = file_rewrite_pluginfile_urls( 468 $description, 469 'pluginfile.php', 470 $this->get_context_id(), 471 'mod_bigbluebuttonbn', 472 'intro', 473 null 474 ); 475 } 476 477 return $description; 478 } 479 480 /** 481 * Get the meeting type if set. 482 * 483 * @return null|string 484 */ 485 public function get_type(): ?string { 486 return $this->get_instance_var('type'); 487 } 488 489 /** 490 * Whether this instance is includes both a room, and recordings. 491 * 492 * @return bool 493 */ 494 public function is_type_room_and_recordings(): bool { 495 return $this->get_type() == self::TYPE_ALL; 496 } 497 498 /** 499 * Whether this instance is one that only includes a room. 500 * 501 * @return bool 502 */ 503 public function is_type_room_only(): bool { 504 return $this->get_type() == self::TYPE_ROOM_ONLY; 505 } 506 507 /** 508 * Whether this instance is one that only includes recordings. 509 * 510 * @return bool 511 */ 512 public function is_type_recordings_only(): bool { 513 return $this->get_type() == self::TYPE_RECORDING_ONLY; 514 } 515 516 /** 517 * Get the participant list for the session. 518 * 519 * @return array 520 */ 521 public function get_participant_list(): array { 522 if ($this->participantlist === null) { 523 $this->participantlist = roles::get_participant_list( 524 $this->get_instance_data(), 525 $this->get_context() 526 ); 527 } 528 529 return $this->participantlist; 530 } 531 532 /** 533 * Get the user. 534 * 535 * @return stdClass 536 */ 537 public function get_user(): stdClass { 538 global $USER; 539 540 return $USER; 541 } 542 543 /** 544 * Get the id of the user. 545 * 546 * @return int 547 */ 548 public function get_user_id(): int { 549 $user = $this->get_user(); 550 551 return $user->id; 552 } 553 554 /** 555 * Get the fullname of the current user. 556 * 557 * @return string 558 */ 559 public function get_user_fullname(): string { 560 $user = $this->get_user(); 561 562 return fullname($user); 563 } 564 565 /** 566 * Whether the current user is an administrator. 567 * 568 * @return bool 569 */ 570 public function is_admin(): bool { 571 global $USER; 572 573 return is_siteadmin($USER->id); 574 } 575 576 /** 577 * Whether the user is a session moderator. 578 * 579 * @return bool 580 */ 581 public function is_moderator(): bool { 582 return roles::is_moderator( 583 $this->get_context(), 584 $this->get_participant_list() 585 ); 586 } 587 588 /** 589 * Whether this user can join the conference. 590 * 591 * This checks the user right for access against capabilities and group membership 592 * 593 * @return bool 594 */ 595 public function can_join(): bool { 596 $groupid = $this->get_group_id(); 597 $context = $this->get_context(); 598 $inrightgroup = 599 groups_group_visible($groupid, $this->get_course(), $this->get_cm()); 600 $hascapability = has_capability('moodle/category:manage', $context) 601 || (has_capability('mod/bigbluebuttonbn:join', $context) && $inrightgroup); 602 $canjoin = $this->get_type() != self::TYPE_RECORDING_ONLY && $hascapability; // Recording only cannot be joined ever. 603 return $canjoin; 604 } 605 606 /** 607 * Whether this user can manage recordings. 608 * 609 * @return bool 610 */ 611 public function can_manage_recordings(): bool { 612 // Note: This will include site administrators. 613 // The has_capability() function returns truthy for admins unless otherwise directed. 614 return has_capability('mod/bigbluebuttonbn:managerecordings', $this->get_context()); 615 } 616 617 /** 618 * Whether this user can publish/unpublish/protect/unprotect/delete recordings. 619 * 620 * @param string $action 621 * @return bool 622 */ 623 public function can_perform_on_recordings($action): bool { 624 // Note: This will include site administrators. 625 // The has_capability() function returns truthy for admins unless otherwise directed. 626 return has_capability("mod/bigbluebuttonbn:{$action}recordings", $this->get_context()); 627 } 628 629 /** 630 * Get the configured user limit. 631 * 632 * @return int 633 */ 634 public function get_user_limit(): int { 635 if ((boolean) config::get('userlimit_editable')) { 636 return intval($this->get_instance_var('userlimit')); 637 } 638 639 return intval((int) config::get('userlimit_default')); 640 } 641 642 /** 643 * Check whether the user limit has been reached. 644 * 645 * @param int $currentusercount The user count to check 646 * @return bool 647 */ 648 public function has_user_limit_been_reached(int $currentusercount): bool { 649 $userlimit = $this->get_user_limit(); 650 if (empty($userlimit)) { 651 return false; 652 } 653 654 return $currentusercount >= $userlimit; 655 } 656 657 /** 658 * Check whether the current user counts towards the user limit. 659 * 660 * @return bool 661 */ 662 public function does_current_user_count_towards_user_limit(): bool { 663 if ($this->is_admin()) { 664 return false; 665 } 666 667 if ($this->is_moderator()) { 668 return false; 669 } 670 671 return true; 672 } 673 674 /** 675 * Get the voice bridge details. 676 * 677 * @return null|int 678 */ 679 public function get_voice_bridge(): ?int { 680 $voicebridge = (int) $this->get_instance_var('voicebridge'); 681 if ($voicebridge > 0) { 682 return 70000 + $voicebridge; 683 } 684 685 return null; 686 } 687 688 /** 689 * Whether participants are muted on entry. 690 * 691 * @return bool 692 */ 693 public function get_mute_on_start(): bool { 694 return $this->get_instance_var('muteonstart'); 695 } 696 697 /** 698 * Get the moderator password. 699 * 700 * @return string 701 */ 702 public function get_moderator_password(): string { 703 return $this->get_instance_var('moderatorpass'); 704 } 705 706 /** 707 * Get the viewer password. 708 * 709 * @return string 710 */ 711 public function get_viewer_password(): string { 712 return $this->get_instance_var('viewerpass'); 713 } 714 715 /** 716 * Get the appropriate password for the current user. 717 * 718 * @return string 719 */ 720 public function get_current_user_password(): string { 721 if ($this->is_admin() || $this->is_moderator()) { 722 return $this->get_moderator_password(); 723 } 724 725 return $this->get_viewer_password(); 726 } 727 728 /** 729 * Get the appropriate designated role for the current user. 730 * 731 * @return string 732 */ 733 public function get_current_user_role(): string { 734 if ($this->is_admin() || $this->is_moderator()) { 735 return 'MODERATOR'; 736 } 737 738 return 'VIEWER'; 739 } 740 741 /** 742 * Whether to show the recording button 743 * 744 * @return bool 745 */ 746 public function should_show_recording_button(): bool { 747 global $CFG; 748 if (!empty($CFG->bigbluebuttonbn_recording_hide_button_editable)) { 749 $recordhidebutton = (bool) $this->get_instance_var('recordhidebutton'); 750 $recordallfromstart = (bool) $this->get_instance_var('recordallfromstart'); 751 return !($recordhidebutton || $recordallfromstart); 752 } 753 754 return !$CFG->bigbluebuttonbn_recording_hide_button_default; 755 } 756 757 /** 758 * Whether this instance is recorded. 759 * 760 * @return bool 761 */ 762 public function is_recorded(): bool { 763 return (bool) $this->get_instance_var('record'); 764 } 765 766 /** 767 * Whether this instance can import recordings from another instance. 768 * 769 * @return bool 770 */ 771 public function can_import_recordings(): bool { 772 if (!config::get('importrecordings_enabled')) { 773 return false; 774 } 775 if ($this->can_manage_recordings()) { 776 return true; 777 } 778 779 return $this->is_feature_enabled('importrecordings'); 780 } 781 782 /** 783 * Get recordings_imported from instancedata. 784 * 785 * @return bool 786 */ 787 public function get_recordings_imported(): bool { 788 if (config::get('recordings_imported_editable')) { 789 return (bool) $this->get_instance_var('recordings_imported'); 790 } 791 return config::get('recordings_imported_default'); 792 } 793 794 /** 795 * Whether this instance is recorded from the start. 796 * 797 * @return bool 798 */ 799 public function should_record_from_start(): bool { 800 if (!$this->is_recorded()) { 801 // This meeting is not recorded. 802 return false; 803 } 804 805 return (bool) $this->get_instance_var('recordallfromstart'); 806 } 807 808 /** 809 * Whether recording can be started and stopped. 810 * 811 * @return bool 812 */ 813 public function allow_recording_start_stop(): bool { 814 if (!$this->is_recorded()) { 815 // If the meeting is not configured for recordings, do not allow it to be recorded. 816 return false; 817 } 818 819 return $this->should_show_recording_button(); 820 } 821 822 /** 823 * Get the welcome message to display. 824 * 825 * @return string 826 */ 827 public function get_welcome_message(): string { 828 $welcomestring = $this->get_instance_var('welcome'); 829 if (!config::get('welcome_editable') || empty($welcomestring)) { 830 $welcomestring = config::get('welcome_default'); 831 } 832 if (empty($welcomestring)) { 833 $welcomestring = get_string('mod_form_field_welcome_default', 'bigbluebuttonbn'); 834 } 835 836 $welcome = [$welcomestring]; 837 838 if ($this->is_recorded()) { 839 if ($this->should_record_from_start()) { 840 $welcome[] = get_string('bbbrecordallfromstartwarning', 'bigbluebuttonbn'); 841 } else { 842 $welcome[] = get_string('bbbrecordwarning', 'bigbluebuttonbn'); 843 } 844 } 845 846 return implode('<br><br>', $welcome); 847 } 848 849 /** 850 * Get the presentation data for internal use. 851 * 852 * The URL returned for the presentation will be accessible through moodle with checks about user being logged in. 853 * 854 * @return array|null 855 */ 856 public function get_presentation(): ?array { 857 return $this->do_get_presentation_with_nonce(false); 858 } 859 860 /** 861 * Get the presentation data for external API url. 862 * 863 * The URL returned for the presentation will be accessible publicly but once and with a specific URL. 864 * 865 * @return array|null 866 */ 867 public function get_presentation_for_bigbluebutton_upload(): ?array { 868 return $this->do_get_presentation_with_nonce(true); 869 } 870 871 /** 872 * Generate Presentation URL. 873 * 874 * @param bool $withnonce The generated url will have a nonce included 875 * @return array|null 876 */ 877 protected function do_get_presentation_with_nonce(bool $withnonce): ?array { 878 if ($this->has_ended()) { 879 return files::get_presentation( 880 $this->get_context(), 881 $this->get_instance_var('presentation'), 882 null, 883 $withnonce 884 ); 885 } else if ($this->is_currently_open()) { 886 return files::get_presentation( 887 $this->get_context(), 888 $this->get_instance_var('presentation'), 889 $this->get_instance_id(), 890 $withnonce 891 ); 892 } else { 893 return []; 894 } 895 } 896 897 /** 898 * Whether the current time is before the scheduled start time. 899 * 900 * @return bool 901 */ 902 public function before_start_time(): bool { 903 $openingtime = $this->get_instance_var('openingtime'); 904 if (empty($openingtime)) { 905 return false; 906 } 907 908 return $openingtime >= time(); 909 } 910 911 /** 912 * Whether the meeting time has passed. 913 * 914 * @return bool 915 */ 916 public function has_ended(): bool { 917 $closingtime = $this->get_instance_var('closingtime'); 918 if (empty($closingtime)) { 919 return false; 920 } 921 922 return $closingtime < time(); 923 } 924 925 /** 926 * Whether this session is currently open. 927 * 928 * @return bool 929 */ 930 public function is_currently_open(): bool { 931 if ($this->before_start_time()) { 932 return false; 933 } 934 935 if ($this->has_ended()) { 936 return false; 937 } 938 939 return true; 940 } 941 942 /** 943 * Whether the user must wait to join the session. 944 * 945 * @return bool 946 */ 947 public function user_must_wait_to_join(): bool { 948 if ($this->is_admin() || $this->is_moderator()) { 949 return false; 950 } 951 952 return (bool) $this->get_instance_var('wait'); 953 } 954 955 /** 956 * Whether the user can force join in all cases 957 * 958 * @return bool 959 */ 960 public function user_can_force_join(): bool { 961 return $this->is_admin() || $this->is_moderator(); 962 } 963 964 /** 965 * Whether the user can end a meeting 966 * 967 * @return bool 968 */ 969 public function user_can_end_meeting(): bool { 970 return $this->is_admin() || $this->is_moderator(); 971 } 972 973 /** 974 * Get information about the origin. 975 * 976 * @return stdClass 977 */ 978 public function get_origin_data(): stdClass { 979 global $CFG; 980 981 $parsedurl = parse_url($CFG->wwwroot); 982 return (object) [ 983 'origin' => 'Moodle', 984 'originVersion' => $CFG->release, 985 'originServerName' => $parsedurl['host'], 986 'originServerUrl' => $CFG->wwwroot, 987 'originServerCommonName' => '', 988 'originTag' => sprintf('moodle-mod_bigbluebuttonbn (%s)', get_config('mod_bigbluebuttonbn', 'version')), 989 ]; 990 } 991 992 /** 993 * Whether this is a server belonging to blindside networks. 994 * 995 * @return bool 996 */ 997 public function is_blindside_network_server(): bool { 998 return bigbluebutton_proxy::is_bn_server(); 999 } 1000 1001 /** 1002 * Get the URL used to access the course that the instance is in. 1003 * 1004 * @return moodle_url 1005 */ 1006 public function get_course_url(): moodle_url { 1007 return new moodle_url('/course/view.php', ['id' => $this->get_course_id()]); 1008 } 1009 1010 /** 1011 * Get the URL used to view the instance as a user. 1012 * 1013 * @return moodle_url 1014 */ 1015 public function get_view_url(): moodle_url { 1016 return new moodle_url('/mod/bigbluebuttonbn/view.php', [ 1017 'id' => $this->cm->id, 1018 ]); 1019 } 1020 1021 /** 1022 * Get the logout URL used to log out of the meeting. 1023 * 1024 * @return moodle_url 1025 */ 1026 public function get_logout_url(): moodle_url { 1027 return new moodle_url('/mod/bigbluebuttonbn/bbb_view.php', [ 1028 'action' => 'logout', 1029 'id' => $this->cm->id, 1030 ]); 1031 } 1032 1033 /** 1034 * Get the URL that the remote server will use to notify that the recording is ready. 1035 * 1036 * @return moodle_url 1037 */ 1038 public function get_record_ready_url(): moodle_url { 1039 return new moodle_url('/mod/bigbluebuttonbn/bbb_broker.php', [ 1040 'action' => 'recording_ready', 1041 'bigbluebuttonbn' => $this->instancedata->id, 1042 ]); 1043 } 1044 1045 /** 1046 * Get the URL that the remote server will use to notify of meeting events. 1047 * 1048 * @return moodle_url 1049 */ 1050 public function get_meeting_event_notification_url(): moodle_url { 1051 return new moodle_url('/mod/bigbluebuttonbn/bbb_broker.php', [ 1052 'action' => 'meeting_events', 1053 'bigbluebuttonbn' => $this->instancedata->id, 1054 ]); 1055 } 1056 1057 /** 1058 * Get the URL used to join a meeting. 1059 * 1060 * @return moodle_url 1061 */ 1062 public function get_join_url(): moodle_url { 1063 return new moodle_url('/mod/bigbluebuttonbn/bbb_view.php', [ 1064 'action' => 'join', 1065 'id' => $this->cm->id, 1066 'bn' => $this->instancedata->id, 1067 ]); 1068 } 1069 1070 /** 1071 * Get the URL used for the import page. 1072 * 1073 * @return moodle_url 1074 */ 1075 public function get_import_url(): moodle_url { 1076 return new moodle_url('/mod/bigbluebuttonbn/import_view.php', [ 1077 'destbn' => $this->instancedata->id, 1078 ]); 1079 } 1080 1081 /** 1082 * Get the list of enabled features for this instance. 1083 * 1084 * @return array 1085 */ 1086 public function get_enabled_features(): array { 1087 return config::get_enabled_features( 1088 bigbluebutton_proxy::get_instance_type_profiles(), 1089 $this->get_instance_var('type') ?? null 1090 ); 1091 } 1092 1093 /** 1094 * Check whetherthe named features is enabled. 1095 * 1096 * @param string $feature 1097 * @return bool 1098 */ 1099 public function is_feature_enabled(string $feature): bool { 1100 $features = $this->get_enabled_features(); 1101 1102 return !empty($features[$feature]); 1103 } 1104 1105 /** 1106 * Check if meeting is recorded. 1107 * 1108 * @return bool 1109 */ 1110 public function should_record() { 1111 return (boolean) config::recordings_enabled() && $this->is_recorded(); 1112 } 1113 1114 /** 1115 * Get recordings for this instance 1116 * 1117 * @param string[] $excludedid 1118 * @param bool $viewdeleted view deleted recordings ? 1119 * @return recording[] 1120 */ 1121 public function get_recordings(array $excludedid = [], bool $viewdeleted = false): array { 1122 // Fetch the list of recordings depending on the status of the instance. 1123 // show room is enabled for TYPE_ALL and TYPE_ROOM_ONLY. 1124 if ($this->is_feature_enabled('showroom')) { 1125 // Not in the import page. 1126 return recording::get_recordings_for_instance( 1127 $this, 1128 $this->is_feature_enabled('importrecordings'), 1129 $this->get_instance_var('recordings_imported'), 1130 ); 1131 } 1132 // We show all recording from this course as this is TYPE_RECORDING. 1133 return recording::get_recordings_for_course( 1134 $this->get_course_id(), 1135 $excludedid, 1136 $this->is_feature_enabled('importrecordings'), 1137 false, 1138 $viewdeleted 1139 ); 1140 } 1141 1142 /** 1143 * Check if this is a valid group for this user/instance, 1144 * 1145 * 1146 * @param stdClass $user 1147 * @param int $groupid 1148 * @return bool 1149 */ 1150 public function user_has_group_access($user, $groupid) { 1151 $cm = $this->get_cm(); 1152 $context = $this->get_context(); 1153 // Then validate group. 1154 $groupmode = groups_get_activity_groupmode($cm); 1155 if ($groupmode && $groupid) { 1156 $accessallgroups = has_capability('moodle/site:accessallgroups', $context); 1157 if ($accessallgroups || $groupmode == VISIBLEGROUPS) { 1158 $allowedgroups = groups_get_all_groups($cm->course, 0, $cm->groupingid); 1159 } else { 1160 $allowedgroups = groups_get_all_groups($cm->course, $user->id, $cm->groupingid); 1161 } 1162 if (!array_key_exists($groupid, $allowedgroups)) { 1163 return false; 1164 } 1165 if (!groups_group_visible($groupid, $this->get_course(), $this->get_cm())) { 1166 return false; 1167 } 1168 } 1169 return true; 1170 } 1171 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body