MDL-71330 mod_chat: Implement the activity dates functionality

This commit is contained in:
Dongsheng Cai 2021-04-20 14:29:22 +10:00
parent 146a38dc45
commit b927b0eac3
7 changed files with 356 additions and 27 deletions

View File

@ -0,0 +1,57 @@
<?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/>.
/**
* Contains the class for fetching the important dates in mod_chat for a given module instance and a user.
*
* @package mod_chat
* @copyright 2021 Dongsheng Cai
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
declare(strict_types=1);
namespace mod_chat;
use core\activity_dates;
/**
* Class for fetching the important dates in mod_chat for a given module instance and a user.
*
*/
class dates extends activity_dates {
/**
* Returns a list of important dates in mod_chat.
*
* @return array
*/
protected function get_dates(): array {
$customdata = $this->cm->customdata;
$chat = (object) $customdata;
$chattime = $chat->chattime ?? 0;
$now = time();
if (!empty($chat->schedule) && $chattime > $now) {
return [
[
'label' => get_string('nextchattime', 'mod_chat'),
'timestamp' => (int) $chattime
]
];
}
return [];
}
}

View File

@ -63,6 +63,7 @@ $string['chat:readlog'] = 'View chat logs';
$string['chatreport'] = 'Chat sessions';
$string['chat:talk'] = 'Talk in a chat';
$string['chattime'] = 'Next chat time';
$string['nextchattime'] = 'Next chat time:';
$string['chat:view'] = 'View chat activity';
$string['entermessage'] = "Enter your message";
$string['eventmessagesent'] = 'Message sent';
@ -157,7 +158,7 @@ $string['serverip'] = 'Server ip';
$string['servermax'] = 'Max users';
$string['serverport'] = 'Server port';
$string['sessions'] = 'Chat sessions';
$string['sessionstart'] = 'The next chat session will start on {$a->date}, ({$a->fromnow} from now)';
$string['sessionstartsin'] = 'The next chat session will start {$a} from now.';
$string['strftimemessage'] = '%H:%M';
$string['studentseereports'] = 'Everyone can view past sessions';
$string['studentseereports_help'] = 'If set to No, only users have mod/chat:readlog capability are able to see the chat logs';
@ -174,3 +175,5 @@ $string['usingchat_help'] = 'The chat module contains some features to make chat
* Beeps - You can send a sound to other participants by clicking the "beep" link next to their name. A useful shortcut to beep all the people in the chat at once is to type "beep all".
* HTML - If you know some HTML code, you can use it in your text to do things like insert images, play sounds or create different coloured text';
$string['viewreport'] = 'View past chat sessions';
// Deprecated since Moodle 3.11.
$string['sessionstart'] = 'The next chat session will start on {$a->date}, ({$a->fromnow} from now)';

View File

@ -0,0 +1 @@
sessionstart,mod_chat

View File

@ -31,6 +31,14 @@ define('CHAT_EVENT_TYPE_CHATTIME', 'chattime');
// Gap between sessions. 5 minutes or more of idleness between messages in a chat means the messages belong in different sessions.
define('CHAT_SESSION_GAP', 300);
// Don't publish next chat time
define('CHAT_SCHEDULE_NONE', 0);
// Publish the specified time only.
define('CHAT_SCHEDULE_SINGLE', 1);
// Repeat chat session at the same time daily.
define('CHAT_SCHEDULE_DAILY', 2);
// Repeat chat session at the same time weekly.
define('CHAT_SCHEDULE_WEEKLY', 3);
// The HTML head for the message window to start with (<!-- nix --> is used to get some browsers starting with output.
global $CHAT_HTMLHEAD;
@ -116,6 +124,7 @@ function chat_add_instance($chat) {
global $DB;
$chat->timemodified = time();
$chat->chattime = chat_calculate_next_chat_time($chat->schedule, $chat->chattime);
$returnid = $DB->insert_record("chat", $chat);
@ -159,6 +168,7 @@ function chat_update_instance($chat) {
$chat->timemodified = time();
$chat->id = $chat->instance;
$chat->chattime = chat_calculate_next_chat_time($chat->schedule, $chat->chattime);
$DB->update_record("chat", $chat);
@ -636,6 +646,35 @@ function chat_delete_old_users() {
}
}
/**
* Calculate next chat session time based on schedule.
*
* @param int $schedule
* @param int $chattime
*
* @return int timestamp
*/
function chat_calculate_next_chat_time(int $schedule, int $chattime): int {
$timenow = time();
switch ($schedule) {
case CHAT_SCHEDULE_DAILY: { // Repeat daily.
while ($chattime <= $timenow) {
$chattime += DAYSECS;
}
break;
}
case CHAT_SCHEDULE_WEEKLY: { // Repeat weekly.
while ($chattime <= $timenow) {
$chattime += WEEKSECS;
}
break;
}
}
return $chattime;
}
/**
* Updates chat records so that the next chat time is correct
*
@ -661,29 +700,18 @@ function chat_update_chat_times($chatid=0) {
}
}
$courseids = [];
foreach ($chats as $chat) {
switch ($chat->schedule) {
case 1: // Single event - turn off schedule and disable.
$chat->chattime = 0;
$chat->schedule = 0;
break;
case 2: // Repeat daily.
while ($chat->chattime <= $timenow) {
$chat->chattime += 24 * 3600;
}
break;
case 3: // Repeat weekly.
while ($chat->chattime <= $timenow) {
$chat->chattime += 7 * 24 * 3600;
}
break;
$originalchattime = $chat->chattime;
$chat->chattime = chat_calculate_next_chat_time($chat->schedule, $chat->chattime);
if ($originalchattime != $chat->chattime) {
$courseids[] = $chat->course;
}
$DB->update_record("chat", $chat);
$event = new stdClass(); // Update calendar too.
$cond = "modulename='chat' AND instance = :chatid AND timestart <> :chattime";
$params = array('chattime' => $chat->chattime, 'chatid' => $chat->id);
$cond = "modulename='chat' AND eventtype = :eventtype AND instance = :chatid AND timestart <> :chattime";
$params = ['chattime' => $chat->chattime, 'eventtype' => CHAT_EVENT_TYPE_CHATTIME, 'chatid' => $chat->id];
if ($event->id = $DB->get_field_select('event', 'id', $cond, $params)) {
$event->timestart = $chat->chattime;
@ -692,6 +720,11 @@ function chat_update_chat_times($chatid=0) {
$calendarevent->update($event, false);
}
}
$courseids = array_unique($courseids);
foreach ($courseids as $courseid) {
rebuild_course_cache($courseid, true);
}
}
/**
@ -1536,3 +1569,39 @@ function chat_get_session_messages($chatid, $group = false, $start = 0, $end = 0
return $DB->get_records_select('chat_messages', $select, $params, $sort);
}
/**
* Add a get_coursemodule_info function in case chat instance wants to add 'extra' information
* for the course (see resource).
*
* Given a course_module object, this function returns any "extra" information that may be needed
* when printing this activity in a course listing. See get_array_of_activities() in course/lib.php.
*
* @param stdClass $coursemodule The coursemodule object (record).
* @return cached_cm_info An object on information that the courses
* will know about (most noticeably, an icon).
*/
function chat_get_coursemodule_info($coursemodule) {
global $DB;
$dbparams = ['id' => $coursemodule->instance];
$fields = 'id, name, intro, introformat, chattime, schedule';
if (!$chat = $DB->get_record('chat', $dbparams, $fields)) {
return false;
}
$result = new cached_cm_info();
$result->name = $chat->name;
if ($coursemodule->showdescription) {
// Convert intro to html. Do not filter cached version, filters run at display time.
$result->content = format_module_intro('chat', $chat, $coursemodule->id, false);
}
// Populate some other values that can be used in calendar or on dashboard.
if ($chat->chattime) {
$result->customdata['chattime'] = $chat->chattime;
$result->customdata['schedule'] = $chat->schedule;
}
return $result;
}

View File

@ -0,0 +1,76 @@
<?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/>.
/**
* Steps definitions related to mod_chat.
*
* @package mod_chat
* @category test
* @copyright 2021 Dongsheng Cai
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../../../../lib/behat/behat_base.php');
/**
* Steps definitions related to mod_chat.
*
*/
class behat_mod_chat extends behat_base {
/**
* Convert page names to URLs for steps like 'When I am on the "[identifier]" "[page type]" page'.
*
* Recognised page names are:
* | pagetype | name meaning | description |
* | View | Chat name | The chat info page (view.php) |
*
* @param string $type identifies which type of page this is, e.g. 'View'.
* @param string $name chat instance name
* @return moodle_url the corresponding URL.
* @throws Exception with a meaningful error message if the specified page cannot be found.
*/
protected function resolve_page_instance_url(string $type, string $name): moodle_url {
switch ($type) {
case 'View':
$cm = $this->get_cm_by_chat_name($name);
return new moodle_url('/mod/chat/view.php', ['id' => $cm->id]);
default:
throw new Exception('Unrecognised chat page type "' . $type . '."');
}
}
/**
* Get a chat by name.
*
* @param string $name chat name.
* @return stdClass the corresponding DB row.
*/
protected function get_chat_by_name(string $name): stdClass {
global $DB;
return $DB->get_record('chat', ['name' => $name], '*', MUST_EXIST);
}
/**
* Get a chat coursemodule object from the name.
*
* @param string $name chat name.
* @return stdClass cm from get_coursemodule_from_instance.
*/
protected function get_cm_by_chat_name(string $name): stdClass {
$chat = $this->get_chat_by_name($name);
return get_coursemodule_from_instance('chat', $chat->id, $chat->course);
}
}

View File

@ -0,0 +1,127 @@
<?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/>.
/**
* Contains unit tests for mod_chat\dates.
*
* @package mod_chat
* @category test
* @copyright 2021 Dongsheng Cai
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
declare(strict_types=1);
namespace mod_chat;
use advanced_testcase;
use cm_info;
use core\activity_dates;
/**
* Class for unit testing mod_chat\dates.
*/
class dates_test extends advanced_testcase {
/**
* Data provider for get_dates_for_module().
* @return array[]
*/
public function get_dates_for_module_provider(): array {
global $CFG;
require_once($CFG->dirroot . '/mod/chat/lib.php');
$now = time();
$past = $now - DAYSECS;
$future = $now + DAYSECS;
$dailynextchattime = $past + 2 * DAYSECS;
$weeklynextchattime = $past + 7 * DAYSECS;
$label = get_string('nextchattime', 'mod_chat');
return [
'chattime in the past' => [
$past, CHAT_SCHEDULE_NONE, []
],
'chattime in the past' => [
$past, CHAT_SCHEDULE_SINGLE, []
],
'chattime in the future' => [
$future, CHAT_SCHEDULE_SINGLE, [
[
'label' => $label,
'timestamp' => $future
],
]
],
'future chattime weekly' => [
$future, CHAT_SCHEDULE_WEEKLY, [
[
'label' => $label,
'timestamp' => $future
]
]
],
'future chattime daily' => [
$future, CHAT_SCHEDULE_DAILY, [
[
'label' => $label,
'timestamp' => $future
]
]
],
'past chattime daily' => [
$past, CHAT_SCHEDULE_DAILY, [
[
'label' => $label,
'timestamp' => $dailynextchattime
],
]
],
'past chattime weekly' => [
$past, CHAT_SCHEDULE_WEEKLY, [
[
'label' => $label,
'timestamp' => $weeklynextchattime
],
]
],
];
}
/**
* Test for get_dates_for_module().
*
* @dataProvider get_dates_for_module_provider
* @param int|null $chattime
* @param int|null $schedule
* @param array $expected The expected value of calling get_dates_for_module()
*/
public function test_get_dates_for_module(?int $chattime, ?int $schedule, array $expected) {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$user = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->enrol_user($user->id, $course->id);
$chat = ['course' => $course->id];
$chat['chattime'] = $chattime;
$chat['schedule'] = $schedule;
$modchat = $this->getDataGenerator()->create_module('chat', $chat);
$this->setUser($user);
$cm = get_coursemodule_from_instance('chat', $modchat->id);
$cminfo = cm_info::create($cm);
$dates = activity_dates::get_dates_for_module($cminfo, (int) $user->id);
$this->assertEquals($expected, $dates);
}
}

View File

@ -122,14 +122,10 @@ if (has_capability('mod/chat:chat', $context)) {
echo $OUTPUT->box_start('generalbox', 'enterlink');
$now = time();
$span = $chat->chattime - $now;
if ($chat->chattime and $chat->schedule and ($span > 0)) { // A chat is scheduled.
echo '<p>';
$chatinfo = new stdClass();
$chatinfo->date = userdate($chat->chattime);
$chatinfo->fromnow = format_time($span);
echo get_string('sessionstart', 'chat', $chatinfo);
echo '</p>';
$chattime = $chat->chattime ?? 0;
$span = $chattime - $now;
if (!empty($chat->schedule) && $span > 0) {
echo html_writer::tag('p', get_string('sessionstartsin', 'chat', format_time($span)));
}
$params['id'] = $chat->id;