MDL-83889 mod_bigbluebuttonbn: Add date classes and tests

This commit is contained in:
Laurent David
2025-08-18 08:05:16 +02:00
parent 2b96047622
commit f6da0c1ff0
7 changed files with 469 additions and 26 deletions
@@ -0,0 +1,5 @@
issueNumber: MDL-83889
notes:
mod_bigbluebuttonbn:
- message: Add activity_dates class to BigblueButton module.
type: improved
@@ -0,0 +1,116 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace mod_bigbluebuttonbn;
use cm_info;
use core\activity_dates;
/**
* Class for fetching the important dates in mod_bigbluebuttonbn for a given module instance and a user.
*
* @package mod_bigbluebuttonbn
* @copyright 2025 Laurent David <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class dates extends activity_dates {
/**
* Returns the activity due date.
*
* @var int|null $timeclose the activity due date
*/
protected ?int $timeclose = null;
/**
* @var int|null $timeopen the activity open date
*/
protected ?int $timeopen = null;
/**
* @var instance the instance of the activity
*/
protected instance $instance;
/**
* activity_dates constructor.
*
* @param cm_info $cm course module
* @param int $userid user id
*/
public function __construct(cm_info $cm, int $userid) {
parent::__construct($cm, $userid);
$this->instance = instance::get_from_cmid((int) $cm->id);
}
/**
* Returns a list of important dates in mod_choice
*
* @return array
*/
protected function get_dates(): array {
$timeopen = $this->instance->get_instance_var('openingtime');
$timeclose = $this->instance->get_instance_var('closingtime');
$now = time();
$dates = [];
if ($timeopen) {
$openlabelid = $timeopen > $now ? 'activitydate:opens' : 'activitydate:opened';
$dates[] = [
'dataid' => 'timeopen',
'label' => get_string($openlabelid, 'course'),
'timestamp' => (int) $timeopen,
];
$this->timeopen = (int) $timeopen;
}
if ($timeclose) {
$closelabelid = $timeclose > $now ? 'activitydate:closes' : 'activitydate:closed';
$dates[] = [
'dataid' => 'timeclose',
'label' => get_string($closelabelid, 'course'),
'timestamp' => (int) $timeclose,
];
$this->timeclose = (int) $timeclose;
}
return $dates;
}
/**
* Returns the activity due date.
*
* @return int|null
*/
public function get_close_date(): ?int {
if (!isset($this->timeclose)) {
$this->get_dates();
}
return $this->timeclose;
}
/**
* Returns the activity open date.
*
* @return int|null
*/
public function get_open_date(): ?int {
if (!isset($this->timeopen)) {
$this->get_dates();
}
return $this->timeopen;
}
}
@@ -40,25 +40,6 @@
<span>{{#userdate}} {{startedat}}, {{#str}} strftimetime, core_langconfig{{/str}} {{/userdate}}.</span>
<span class="status-message">{{statusmessage}}</span>
</div>
{{/statusrunning}}
{{^statusrunning}}
<div class="status-message">{{statusmessage}}</div>
{{/statusrunning}}
<div class="conf-opening-time">
{{#openingtime}}
<span class="conf-opening">
<span class="fw-bold">{{#str}}mod_form_field_openingtime, bigbluebuttonbn{{/str}}:</span>
{{#userdate}} {{.}}, {{#str}} strftimedaydatetime, langconfig {{/str}} {{/userdate}}
</span>
{{/openingtime}}
{{#closingtime}}
<div class="conf-closing">
<span class="fw-bold">{{#str}}mod_form_field_closingtime, bigbluebuttonbn{{/str}}:</span>
{{#userdate}} {{.}}, {{#str}} strftimedaydatetime, langconfig {{/str}} {{/userdate}}
</div>
{{/closingtime}}
</div>
{{#statusrunning}}
<div>
<span class="fw-bold">
{{#moderatorplural}}{{#str}}view_message_moderators, mod_bigbluebuttonbn{{/str}}{{/moderatorplural}}
@@ -74,6 +55,9 @@
<span>{{participantcount}}</span>
</div>
{{/statusrunning}}
{{^statusrunning}}
<div class="status-message">{{statusmessage}}</div>
{{/statusrunning}}
</div>
<div id="bigbluebuttonbn-room-view-control-panel" data-bbb-id="{{bigbluebuttonbnid}}" class="mt-2">
@@ -28,9 +28,9 @@ Feature: Manage BigBlueButton session timings
| C1 | bigbluebuttonbn | BBB 1 | <openingtime> | <closingtime> |
When I am on the "BBB 1" "bigbluebuttonbn activity" page logged in as student1
And "Join session" "link" <buttonvisibility> exist
And I should see "Open:"
And I should see "<opens>:"
And I should see "<openingtime>%A, %d %B %Y##"
And I should see "Close:"
And I should see "<closes>:"
And I should see "<closingtime>%A, %d %B %Y##"
And I am viewing calendar in "month" view
And I <calendarvisibility> see "BBB 1"
@@ -39,7 +39,7 @@ Feature: Manage BigBlueButton session timings
And I <upcomingeventvisibility> see "BBB 1" in the "Upcoming events" "block"
Examples:
| openingtime | closingtime | calendarvisibility | buttonvisibility | upcomingeventvisibility |
| ##now +1 minute## | ##now +5 minutes## | should | should not | should |
| ##1 hour ago## | ##+2 hours## | should | should | should not |
| ##yesterday## | ##yesterday +3 hours## | should not | should not | should not |
| opens | closes | openingtime | closingtime | calendarvisibility | buttonvisibility | upcomingeventvisibility |
| Opens | Closes | ##now +1 minute## | ##now +5 minutes## | should | should not | should |
| Opened | Closes | ##1 hour ago## | ##+2 hours## | should | should | should not |
| Opened | Closed | ##yesterday## | ##yesterday +3 hours## | should not | should not | should not |
@@ -0,0 +1,217 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace mod_bigbluebuttonbn;
use advanced_testcase;
use core\activity_dates;
/**
* Class for unit testing mod_bigbluebutton\dates.
*
* @package mod_bigbluebuttonbn
* @copyright 2025 Laurent David <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \mod_bigbluebuttonbn\dates
*/
final class dates_test extends advanced_testcase {
use \mod_bigbluebuttonbn\test\testcase_helper_trait;
/**
* Data provider for get_dates_for_module().
*
* @return array[]
*/
public static function get_dates_for_module_provider(): array {
$clock = \core\di::get(\core\clock::class);
$now = $clock->time();
$open = $now - DAYSECS;
$close = $now + DAYSECS;
return [
'Without any dates' => [
null, null, [],
],
'Only with opening time' => [
$open,
null,
[
[
'label' => get_string('activitydate:opened', 'course'),
'timestamp' => $open,
'dataid' => 'timeopen',
],
],
],
'Only with closing time' => [
null,
$close,
[
[
'label' => get_string('activitydate:closes', 'course'),
'timestamp' => $close,
'dataid' => 'timeclose',
],
],
],
'With both times' => [
$open,
$close,
[
[
'label' => get_string('activitydate:opened', 'course'),
'timestamp' => $open,
'dataid' => 'timeopen',
],
[
'label' => get_string('activitydate:closes', 'course'),
'timestamp' => $close,
'dataid' => 'timeclose',
],
],
],
'With both times in the future' => [
$now + DAYSECS,
$now + (2 * DAYSECS),
[
[
'label' => get_string('activitydate:opens', 'course'),
'timestamp' => $now + DAYSECS,
'dataid' => 'timeopen',
],
[
'label' => get_string('activitydate:closes', 'course'),
'timestamp' => $now + (2 * DAYSECS),
'dataid' => 'timeclose',
],
],
],
'With both times in the past' => [
$now - (2 * DAYSECS),
$now - DAYSECS,
[
[
'label' => get_string('activitydate:opened', 'course'),
'timestamp' => $now - (2 * DAYSECS),
'dataid' => 'timeopen',
],
[
'label' => get_string('activitydate:closed', 'course'),
'timestamp' => $now - DAYSECS,
'dataid' => 'timeclose',
],
],
],
];
}
/**
* Test for get_dates_for_module().
*
* @param int|null $open Opening time in the BigBlueButton.
* @param int|null $close Closing time in the BigBlueButton.
* @param array $expected The expected value of calling get_dates_for_module()
* @covers ::get_dates_for_module
* @dataProvider get_dates_for_module_provider
*/
public function test_get_dates_for_module(
?int $open,
?int $close,
array $expected
): void {
$this->resetAfterTest();
['user' => $user, 'cm' => $cm] = $this->setup_instance($open, $close);
$this->setUser($user);
$dates = activity_dates::get_dates_for_module($cm, (int) $user->id);
$this->assertEquals($expected, $dates);
}
/**
* Test for get_open_date().
*
* @param int|null $open Opening time in the BigBlueButton.
* @param int|null $close Closing time in the BigBlueButton.
* @covers ::get_open_date
* @dataProvider get_dates_for_module_provider
*/
public function test_get_open_date(
?int $open,
?int $close,
): void {
$this->resetAfterTest();
['user' => $user, 'cm' => $cm] = $this->setup_instance($open, $close);
$this->setUser($user);
$dates = new \mod_bigbluebuttonbn\dates($cm, (int) $user->id);
$this->assertEquals($open, $dates->get_open_date());
}
/**
* Test for get_close_date().
*
* @param int|null $open Opening time in the BigBlueButton.
* @param int|null $close Closing time in the BigBlueButton.
* @covers ::get_close_date
* @dataProvider get_dates_for_module_provider
*/
public function test_get_close_date(
?int $open,
?int $close,
): void {
$this->resetAfterTest();
['user' => $user, 'cm' => $cm] = $this->setup_instance($open, $close);
$dates = new \mod_bigbluebuttonbn\dates($cm, (int) $user->id);
$this->assertEquals($close, $dates->get_close_date());
}
/**
* Setup a BigBlueButton activity instance.
*
* @param int|null $open Opening time in the BigBlueButton.
* @param int|null $close Closing time in the BigBlueButton.
* @return array with keys 'user' and 'cm'.
*/
private function setup_instance(
?int $open,
?int $close,
): array {
$generator = $this->getDataGenerator();
$course = $generator->create_course();
$user = $generator->create_user();
$generator->enrol_user($user->id, $course->id);
$data = [];
if ($open !== null) {
$data['openingtime'] = $open;
}
if ($close !== null) {
$data['closingtime'] = $close;
}
$this->setAdminUser();
[$bbactivitycontext, $bbactivitycm, $bbactivity] = $this->create_instance(
$course,
$data
);
return ['user' => $user, 'cm' => $bbactivitycm];
}
}
@@ -69,11 +69,27 @@ class mod_bigbluebuttonbn_generator extends \testing_module_generator {
"recordings_preview" => 0,
"grade" => 0,
];
$record = (array) $record;
$record['participants'] = json_encode($this->get_participants_from_record($record));
if (!empty($record['openingtime'])) {
if (is_numeric($record['openingtime'])) {
$record['openingtime'] = intval($record['openingtime']);
} else {
// If it is a string, we assume it is a timestamp.
$record['openingtime'] = strtotime($record['openingtime']);
}
}
if (!empty($record['closingtime'])) {
if (is_numeric($record['closingtime'])) {
$record['closingtime'] = intval($record['closingtime']);
} else {
// If it is a string, we assume it is a timestamp.
$record['closingtime'] = strtotime($record['closingtime']);
}
}
foreach ($defaults as $key => $value) {
if (!isset($record[$key])) {
$record[$key] = $value;
@@ -0,0 +1,105 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn;
/**
* Genarator tests class for mod_bigbluebuttonbn.
*
* @package mod_bigbluebuttonbn
* @category test
* @copyright 2025 Laurent David <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class generator_test extends \advanced_testcase {
/**
* Test the creation of a bigbluebuttonbn instance.
* @covers \mod_bigbluebuttonbn_generator::create_instance
*/
public function test_create_instance(): void {
$db = \core\di::get(\moodle_database::class);
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$bigbluebuttonbn = $this->getDataGenerator()->create_module('bigbluebuttonbn', ['course' => $course]);
$records = $db->get_records('bigbluebuttonbn', ['course' => $course->id], 'id');
$this->assertEquals(1, count($records));
$this->assertTrue(array_key_exists($bigbluebuttonbn->id, $records));
$params = ['course' => $course->id, 'name' => 'Another bigbluebuttonbn'];
$bigbluebuttonbn = $this->getDataGenerator()->create_module('bigbluebuttonbn', $params);
$records = $db->get_records('bigbluebuttonbn', ['course' => $course->id], 'id');
$this->assertEquals(2, count($records));
$this->assertEquals('Another bigbluebuttonbn', $records[$bigbluebuttonbn->id]->name);
}
/**
* Test the creation of a bigbluebuttonbn instance with a custom name.
*
* @param string|int $opening The opening time as a timestamp or human-readable date.
* @param string|int $closing The closing time as a timestamp or human-readable date
* @param int $expectedopening The expected opening time as a timestamp.
* @param int $expectedclosing The expected closing time as a timestamp.
* @covers \mod_bigbluebuttonbn_generator::create_instance
* @dataProvider provider_create_instance_with_name
*/
public function test_create_instance_with_dates(
string|int $opening,
string|int $closing,
int $expectedopening,
int $expectedclosing
): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$params = ['course' => $course->id, 'openingtime' => $opening, 'closingtime' => $closing];
$bigbluebuttonbn = $this->getDataGenerator()->create_module('bigbluebuttonbn', $params);
$instance = \mod_bigbluebuttonbn\instance::get_from_instanceid($bigbluebuttonbn->id);
$this->assertEquals($expectedopening, $instance->get_instance_var('openingtime'));
$this->assertEquals($expectedclosing, $instance->get_instance_var('closingtime'));
}
/**
* Data provider for test_create_instance_with_dates.
*
* @return array[]
*/
public static function provider_create_instance_with_name(): array {
global $CFG;
require_once($CFG->libdir . '/testing/classes/frozen_clock.php');
$clock = new \frozen_clock();
\core\di::set(\core\clock::class, $clock);
$opening = $clock->time();
$closing = $opening + DAYSECS;
return [
'Timestamp' => [
$opening,
$closing,
$opening,
$closing,
],
'Human date' => [
userdate($opening, get_string('strftimedatetimeaccurate', 'langconfig')),
userdate($closing, get_string('strftimedatetimeaccurate', 'langconfig')),
$opening,
$closing,
],
];
}
}