Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.
   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  /**
  18   * Data provider tests.
  19   *
  20   * @package    mod_chat
  21   * @category   test
  22   * @copyright  2018 Frédéric Massart
  23   * @author     Frédéric Massart <fred@branchup.tech>
  24   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  namespace mod_chat\privacy;
  27  
  28  defined('MOODLE_INTERNAL') || die();
  29  global $CFG;
  30  
  31  use core_privacy\tests\provider_testcase;
  32  use core_privacy\local\request\approved_contextlist;
  33  use core_privacy\local\request\approved_userlist;
  34  use core_privacy\local\request\transform;
  35  use core_privacy\local\request\writer;
  36  use mod_chat\privacy\provider;
  37  
  38  require_once($CFG->dirroot . '/mod/chat/lib.php');
  39  
  40  /**
  41   * Data provider testcase class.
  42   *
  43   * @package    mod_chat
  44   * @category   test
  45   * @copyright  2018 Frédéric Massart
  46   * @author     Frédéric Massart <fred@branchup.tech>
  47   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  48   */
  49  class provider_test extends provider_testcase {
  50  
  51      public function setUp(): void {
  52          global $PAGE;
  53          $this->resetAfterTest();
  54          $PAGE->get_renderer('core');
  55      }
  56  
  57      public function test_get_contexts_for_userid() {
  58          global $DB;
  59          $dg = $this->getDataGenerator();
  60          $c1 = $dg->create_course();
  61          $c2 = $dg->create_course();
  62  
  63          $u1 = $dg->create_user();
  64          $u2 = $dg->create_user();
  65  
  66          $chat1a = $dg->create_module('chat', ['course' => $c1]);
  67          $chat1b = $dg->create_module('chat', ['course' => $c1]);
  68          $chat2a = $dg->create_module('chat', ['course' => $c2]);
  69  
  70          // Logins but no message.
  71          $chatuser = $this->login_user_in_course_chat($u1, $c1, $chat1a);
  72  
  73          // Logins and messages.
  74          $chatuser = $this->login_user_in_course_chat($u1, $c1, $chat1b);
  75          chat_send_chatmessage($chatuser, 'Hello world!');
  76  
  77          // Silent login (no system message).
  78          $chatuser = $this->login_user_in_course_chat($u1, $c2, $chat2a, 0, true);
  79  
  80          // Silent login and messages.
  81          $chatuser = $this->login_user_in_course_chat($u2, $c1, $chat1b, 0, true);
  82          chat_send_chatmessage($chatuser, 'Ça va ?');
  83          chat_send_chatmessage($chatuser, 'Moi, ça va.');
  84  
  85          // Silent login and messages.
  86          $chatuser = $this->login_user_in_course_chat($u2, $c2, $chat2a);
  87          chat_send_chatmessage($chatuser, 'What\'s happening here?');
  88  
  89          // Check contexts for user 1.
  90          $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
  91          $this->assertCount(2, $contextids);
  92          $this->assertTrue(in_array(\context_module::instance($chat1a->cmid)->id, $contextids));
  93          $this->assertTrue(in_array(\context_module::instance($chat1b->cmid)->id, $contextids));
  94  
  95          $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
  96          $this->assertCount(2, $contextids);
  97          $this->assertTrue(in_array(\context_module::instance($chat1b->cmid)->id, $contextids));
  98          $this->assertTrue(in_array(\context_module::instance($chat2a->cmid)->id, $contextids));
  99      }
 100  
 101      /**
 102       * Test that only users with relevant contexts are fetched.
 103       */
 104      public function test_get_users_in_context() {
 105          $component = 'mod_chat';
 106          $dg = $this->getDataGenerator();
 107          $c1 = $dg->create_course();
 108          $c2 = $dg->create_course();
 109  
 110          $u1 = $dg->create_user();
 111          $u2 = $dg->create_user();
 112  
 113          $chat1a = $dg->create_module('chat', ['course' => $c1]);
 114          $chat1b = $dg->create_module('chat', ['course' => $c1]);
 115          $chat2a = $dg->create_module('chat', ['course' => $c2]);
 116  
 117          // Logins but no message.
 118          $chatuser = $this->login_user_in_course_chat($u1, $c1, $chat1a);
 119  
 120          // Logins and messages.
 121          $chatuser = $this->login_user_in_course_chat($u1, $c1, $chat1b);
 122          chat_send_chatmessage($chatuser, 'Hello world!');
 123  
 124          // Silent login (no system message).
 125          $chatuser = $this->login_user_in_course_chat($u1, $c2, $chat2a, 0, true);
 126  
 127          // Silent login and messages.
 128          $chatuser = $this->login_user_in_course_chat($u2, $c1, $chat1b, 0, true);
 129          chat_send_chatmessage($chatuser, 'Ça va ?');
 130          chat_send_chatmessage($chatuser, 'Moi, ça va.');
 131  
 132          // Silent login and messages.
 133          $chatuser = $this->login_user_in_course_chat($u2, $c2, $chat2a);
 134          chat_send_chatmessage($chatuser, 'What\'s happening here?');
 135  
 136          $context1a = \context_module::instance($chat1a->cmid);
 137          $context1b = \context_module::instance($chat1b->cmid);
 138          $context2a = \context_module::instance($chat2a->cmid);
 139  
 140          $userlist1a = new \core_privacy\local\request\userlist($context1a, $component);
 141          $userlist1b = new \core_privacy\local\request\userlist($context1b, $component);
 142          $userlist2a = new \core_privacy\local\request\userlist($context2a, $component);
 143          \mod_chat\privacy\provider::get_users_in_context($userlist1a);
 144          \mod_chat\privacy\provider::get_users_in_context($userlist1b);
 145          \mod_chat\privacy\provider::get_users_in_context($userlist2a);
 146  
 147          // Ensure correct users are found in relevant contexts.
 148          $this->assertCount(1, $userlist1a);
 149          $expected = [$u1->id];
 150          $actual = $userlist1a->get_userids();
 151          $this->assertEquals($expected, $actual);
 152  
 153          $this->assertCount(2, $userlist1b);
 154          $expected = [$u1->id, $u2->id];
 155          $actual = $userlist1b->get_userids();
 156          sort($expected);
 157          sort($actual);
 158          $this->assertEquals($expected, $actual);
 159  
 160          $this->assertCount(1, $userlist2a);
 161          $expected = [$u1->id];
 162          $actual = $userlist1a->get_userids();
 163          $this->assertEquals($expected, $actual);
 164      }
 165  
 166      public function test_delete_data_for_all_users_in_context() {
 167          global $DB;
 168          $dg = $this->getDataGenerator();
 169          $c1 = $dg->create_course();
 170  
 171          $u1 = $dg->create_user();
 172          $u2 = $dg->create_user();
 173  
 174          $chat1a = $dg->create_module('chat', ['course' => $c1]);
 175          $chat1b = $dg->create_module('chat', ['course' => $c1]);
 176          $chat1actx = \context_module::instance($chat1a->cmid);
 177          $chat1bctx = \context_module::instance($chat1b->cmid);
 178  
 179          $u1chat1a = $this->login_user_in_course_chat($u1, $c1, $chat1a);
 180          $u2chat1a = $this->login_user_in_course_chat($u2, $c1, $chat1a);
 181          chat_send_chatmessage($u1chat1a, 'Ça va ?');
 182          chat_send_chatmessage($u2chat1a, 'Oui, et toi ?');
 183          chat_send_chatmessage($u1chat1a, 'Bien merci.');
 184          chat_send_chatmessage($u2chat1a, 'Pourquoi ils disent omelette "du" fromage ?!');
 185          chat_send_chatmessage($u1chat1a, 'Aucune idée');
 186          $this->assert_has_data_in_chat($u1, $chat1a);
 187          $this->assert_has_data_in_chat($u2, $chat1a);
 188  
 189          $u1chat1b = $this->login_user_in_course_chat($u1, $c1, $chat1b);
 190          $u2chat1b = $this->login_user_in_course_chat($u2, $c1, $chat1b);
 191          chat_send_chatmessage($u1chat1b, 'How are you going?');
 192          chat_send_chatmessage($u2chat1b, 'Alright, you?');
 193          chat_send_chatmessage($u1chat1b, 'Good, thanks.');
 194          chat_send_chatmessage($u2chat1b, 'Sacre bleu!');
 195          chat_send_chatmessage($u1chat1b, '\ö/');
 196          $this->assert_has_data_in_chat($u1, $chat1b);
 197          $this->assert_has_data_in_chat($u2, $chat1b);
 198  
 199          // No change.
 200          provider::delete_data_for_all_users_in_context(\context_course::instance($c1->id));
 201          $this->assert_has_data_in_chat($u1, $chat1a);
 202          $this->assert_has_data_in_chat($u2, $chat1a);
 203          $this->assert_has_data_in_chat($u1, $chat1b);
 204          $this->assert_has_data_in_chat($u2, $chat1b);
 205  
 206          // Deletinge first chat does not affect other chat.
 207          provider::delete_data_for_all_users_in_context($chat1actx);
 208          $this->assert_has_no_data_in_chat($u1, $chat1a);
 209          $this->assert_has_no_data_in_chat($u2, $chat1a);
 210          $this->assert_has_data_in_chat($u1, $chat1b);
 211          $this->assert_has_data_in_chat($u2, $chat1b);
 212      }
 213  
 214      public function test_delete_data_for_user() {
 215          global $DB;
 216          $dg = $this->getDataGenerator();
 217          $c1 = $dg->create_course();
 218  
 219          $u1 = $dg->create_user();
 220          $u2 = $dg->create_user();
 221  
 222          $chat1a = $dg->create_module('chat', ['course' => $c1]);
 223          $chat1b = $dg->create_module('chat', ['course' => $c1]);
 224          $chat1actx = \context_module::instance($chat1a->cmid);
 225          $chat1bctx = \context_module::instance($chat1b->cmid);
 226  
 227          $u1chat1a = $this->login_user_in_course_chat($u1, $c1, $chat1a);
 228          $u2chat1a = $this->login_user_in_course_chat($u2, $c1, $chat1a);
 229          chat_send_chatmessage($u1chat1a, 'Ça va ?');
 230          chat_send_chatmessage($u2chat1a, 'Oui, et toi ?');
 231          chat_send_chatmessage($u1chat1a, 'Bien merci.');
 232          chat_send_chatmessage($u2chat1a, 'Pourquoi ils disent omelette "du" fromage ?!');
 233          chat_send_chatmessage($u1chat1a, 'Aucune idée');
 234          $this->assert_has_data_in_chat($u1, $chat1a);
 235          $this->assert_has_data_in_chat($u2, $chat1a);
 236  
 237          $u1chat1b = $this->login_user_in_course_chat($u1, $c1, $chat1b);
 238          $u2chat1b = $this->login_user_in_course_chat($u2, $c1, $chat1b);
 239          chat_send_chatmessage($u1chat1b, 'How are you going?');
 240          chat_send_chatmessage($u2chat1b, 'Alright, you?');
 241          chat_send_chatmessage($u1chat1b, 'Good, thanks.');
 242          chat_send_chatmessage($u2chat1b, 'Sacre bleu!');
 243          chat_send_chatmessage($u1chat1b, '\ö/');
 244          $this->assert_has_data_in_chat($u1, $chat1b);
 245          $this->assert_has_data_in_chat($u2, $chat1b);
 246  
 247          provider::delete_data_for_user(new approved_contextlist($u1, 'mod_chat', [$chat1actx->id]));
 248          $this->assert_has_no_data_in_chat($u1, $chat1a);
 249          $this->assert_has_data_in_chat($u2, $chat1a);
 250          $this->assert_has_data_in_chat($u1, $chat1b);
 251          $this->assert_has_data_in_chat($u2, $chat1b);
 252  
 253          provider::delete_data_for_user(new approved_contextlist($u2, 'mod_chat', [$chat1actx->id, $chat1bctx->id]));
 254          $this->assert_has_no_data_in_chat($u1, $chat1a);
 255          $this->assert_has_no_data_in_chat($u2, $chat1a);
 256          $this->assert_has_data_in_chat($u1, $chat1b);
 257          $this->assert_has_no_data_in_chat($u2, $chat1b);
 258      }
 259  
 260      /**
 261       * Test that data for users in approved userlist is deleted.
 262       */
 263      public function test_delete_data_for_users() {
 264          global $DB;
 265          $component = 'mod_chat';
 266          $dg = $this->getDataGenerator();
 267          $c1 = $dg->create_course();
 268  
 269          $u1 = $dg->create_user();
 270          $u2 = $dg->create_user();
 271          $u3 = $dg->create_user();
 272  
 273          $chat1 = $dg->create_module('chat', ['course' => $c1]);
 274          $chat1context = \context_module::instance($chat1->cmid);
 275  
 276          $u1chat1 = $this->login_user_in_course_chat($u1, $c1, $chat1);
 277          $u2chat1 = $this->login_user_in_course_chat($u2, $c1, $chat1);
 278          $u3chat1 = $this->login_user_in_course_chat($u3, $c1, $chat1);
 279          chat_send_chatmessage($u1chat1, 'Ça va ?');
 280          chat_send_chatmessage($u2chat1, 'Oui, et toi ?');
 281          chat_send_chatmessage($u1chat1, 'Bien merci.');
 282          chat_send_chatmessage($u2chat1, 'Pourquoi ils disent omelette "du" fromage ?!');
 283          chat_send_chatmessage($u1chat1, 'Aucune idée');
 284          chat_send_chatmessage($u3chat1, 'Je ne comprends pas');
 285          $this->assert_has_data_in_chat($u1, $chat1);
 286          $this->assert_has_data_in_chat($u2, $chat1);
 287          $this->assert_has_data_in_chat($u3, $chat1);
 288  
 289          $chat2 = $dg->create_module('chat', ['course' => $c1]);
 290  
 291          $u1chat2 = $this->login_user_in_course_chat($u1, $c1, $chat2);
 292          $u2chat2 = $this->login_user_in_course_chat($u2, $c1, $chat2);
 293          $u3chat2 = $this->login_user_in_course_chat($u3, $c1, $chat2);
 294          chat_send_chatmessage($u1chat2, 'Why do we have a separate chat?');
 295          chat_send_chatmessage($u2chat2, 'I have no idea!');
 296          chat_send_chatmessage($u3chat2, 'Me either.');
 297          $this->assert_has_data_in_chat($u1, $chat2);
 298          $this->assert_has_data_in_chat($u2, $chat2);
 299          $this->assert_has_data_in_chat($u3, $chat2);
 300  
 301          // Delete user 1 and 2 data from chat 1 context only.
 302          $approveduserids = [$u1->id, $u2->id];
 303          $approvedlist = new approved_userlist($chat1context, $component, $approveduserids);
 304          provider::delete_data_for_users($approvedlist);
 305  
 306          // Ensure correct chat data is deleted.
 307          $this->assert_has_no_data_in_chat($u1, $chat1);
 308          $this->assert_has_no_data_in_chat($u2, $chat1);
 309          $this->assert_has_data_in_chat($u3, $chat1);
 310  
 311          $this->assert_has_data_in_chat($u1, $chat2);
 312          $this->assert_has_data_in_chat($u2, $chat2);
 313          $this->assert_has_data_in_chat($u3, $chat2);
 314      }
 315  
 316      public function test_export_data_for_user() {
 317          global $DB;
 318          $dg = $this->getDataGenerator();
 319          $c1 = $dg->create_course();
 320  
 321          $u1 = $dg->create_user();
 322          $u2 = $dg->create_user();
 323  
 324          $chat1a = $dg->create_module('chat', ['course' => $c1]);
 325          $chat1b = $dg->create_module('chat', ['course' => $c1]);
 326          $chat1actx = \context_module::instance($chat1a->cmid);
 327          $chat1bctx = \context_module::instance($chat1b->cmid);
 328  
 329          $u1chat1a = $this->login_user_in_course_chat($u1, $c1, $chat1a);
 330          $u2chat1a = $this->login_user_in_course_chat($u2, $c1, $chat1a);
 331          chat_send_chatmessage($u1chat1a, 'Ça va ?');
 332          chat_send_chatmessage($u2chat1a, 'Oui, et toi ?');
 333          chat_send_chatmessage($u1chat1a, 'Bien merci.');
 334          chat_send_chatmessage($u2chat1a, 'Pourquoi ils disent omelette "du" fromage ?!');
 335          chat_send_chatmessage($u1chat1a, 'Aucune idée');
 336          chat_send_chatmessage($u1chat1a, 'exit', true);
 337  
 338          $u1chat1b = $this->login_user_in_course_chat($u1, $c1, $chat1b);
 339          $u2chat1b = $this->login_user_in_course_chat($u2, $c1, $chat1b);
 340          chat_send_chatmessage($u1chat1b, 'How are you going?');
 341          chat_send_chatmessage($u2chat1b, 'Alright, you?');
 342          chat_send_chatmessage($u1chat1b, 'Good, thanks.');
 343          chat_send_chatmessage($u2chat1b, 'Sacre bleu!');
 344          chat_send_chatmessage($u1chat1b, '\ö/');
 345  
 346          // Export for user 1 in chat 1.
 347          provider::export_user_data(new approved_contextlist($u1, 'mod_chat', [$chat1actx->id]));
 348          $data = writer::with_context($chat1actx)->get_data([]);
 349          $this->assertNotEmpty($data);
 350          $this->assertCount(5, $data->messages);
 351          $this->assertEquals(get_string('messageenter', 'mod_chat', fullname($u1)), $data->messages[0]['message']);
 352          $this->assertEquals(transform::yesno(true), $data->messages[0]['is_system_generated']);
 353          $this->assertEquals('Ça va ?', $data->messages[1]['message']);
 354          $this->assertEquals(transform::yesno(false), $data->messages[1]['is_system_generated']);
 355          $this->assertEquals('Bien merci.', $data->messages[2]['message']);
 356          $this->assertEquals(transform::yesno(false), $data->messages[2]['is_system_generated']);
 357          $this->assertEquals('Aucune idée', $data->messages[3]['message']);
 358          $this->assertEquals(transform::yesno(false), $data->messages[3]['is_system_generated']);
 359          $this->assertEquals(get_string('messageexit', 'mod_chat', fullname($u1)), $data->messages[4]['message']);
 360          $this->assertEquals(transform::yesno(true), $data->messages[4]['is_system_generated']);
 361          $data = writer::with_context($chat1bctx)->get_data([]);
 362          $this->assertEmpty($data);
 363  
 364          // Export for user2 in chat 1 and 2.
 365          writer::reset();
 366          provider::export_user_data(new approved_contextlist($u2, 'mod_chat', [$chat1actx->id, $chat1bctx->id]));
 367          $data = writer::with_context($chat1actx)->get_data([]);
 368          $this->assertNotEmpty($data);
 369          $this->assertCount(3, $data->messages);
 370          $this->assertEquals(get_string('messageenter', 'mod_chat', fullname($u2)), $data->messages[0]['message']);
 371          $this->assertEquals('Oui, et toi ?', $data->messages[1]['message']);
 372          $this->assertEquals('Pourquoi ils disent omelette "du" fromage ?!', $data->messages[2]['message']);
 373          $data = writer::with_context($chat1bctx)->get_data([]);
 374          $this->assertNotEmpty($data);
 375          $this->assertCount(3, $data->messages);
 376          $this->assertEquals(get_string('messageenter', 'mod_chat', fullname($u2)), $data->messages[0]['message']);
 377          $this->assertEquals('Alright, you?', $data->messages[1]['message']);
 378          $this->assertEquals('Sacre bleu!', $data->messages[2]['message']);
 379      }
 380  
 381      /**
 382       * Assert that there is data for a user in a chat.
 383       *
 384       * @param object $user The user.
 385       * @param object $chat The chat.
 386       * @return void
 387       */
 388      protected function assert_has_data_in_chat($user, $chat) {
 389          $this->assertTrue($this->has_data_in_chat($user, $chat));
 390      }
 391  
 392      /**
 393       * Assert that there isn't any data for a user in a chat.
 394       *
 395       * @param object $user The user.
 396       * @param object $chat The chat.
 397       * @return void
 398       */
 399      protected function assert_has_no_data_in_chat($user, $chat) {
 400          $this->assertFalse($this->has_data_in_chat($user, $chat));
 401      }
 402  
 403      /**
 404       * Check whether a user has data in a chat.
 405       *
 406       * @param object $user The user.
 407       * @param object $chat The chat.
 408       * @return bool
 409       */
 410      protected function has_data_in_chat($user, $chat) {
 411          global $DB;
 412          return $DB->record_exists('chat_messages', ['chatid' => $chat->id, 'userid' => $user->id]);
 413      }
 414  
 415      /**
 416       * Login a user in a chat.
 417       *
 418       * @param object $user The user.
 419       * @param object $course The course.
 420       * @param object $chat The chat.
 421       * @param int $group The group number.
 422       * @param bool $silent Whether we should advertise that the user logs in.
 423       * @return object The chat user.
 424       */
 425      protected function login_user_in_course_chat($user, $course, $chat, $group = 0, $silent = false) {
 426          global $DB, $USER;
 427          $origuser = $USER;
 428          $this->setUser($user);
 429          chat_login_user($chat->id, $silent ? 'sockets' : 'basic', 0, $course);
 430          $chatuser = $DB->get_record('chat_users', ['userid' => $user->id, 'chatid' => $chat->id, 'groupid' => 0]);
 431          $this->setUser($origuser);
 432          return $chatuser;
 433      }
 434  }