Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
   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   * Events tests.
  19   *
  20   * @package    core_blog
  21   * @category   test
  22   * @copyright  2016 Stephen Bourget
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  namespace core_blog\event;
  27  
  28  defined('MOODLE_INTERNAL') || die();
  29  
  30  global $CFG;
  31  require_once($CFG->dirroot . '/blog/locallib.php');
  32  require_once($CFG->dirroot . '/blog/lib.php');
  33  
  34  /**
  35   * Unit tests for the blog events.
  36   *
  37   * @copyright  2016 Stephen Bourget
  38   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  39   */
  40  class events_test extends \advanced_testcase {
  41  
  42      /** @var $courseid */
  43      private $courseid;
  44  
  45      /** @var $cmid */
  46      private $cmid;
  47  
  48      /** @var $groupid */
  49      private $groupid;
  50  
  51      /** @var $userid */
  52      private $userid;
  53  
  54      /** @var $tagid */
  55      private $tagid;
  56  
  57      /** @var $postid */
  58      private $postid;
  59  
  60      /**
  61       * Setup the tests.
  62       */
  63      protected function setUp(): void {
  64          global $DB;
  65          parent::setUp();
  66  
  67          $this->resetAfterTest();
  68  
  69          // Create default course.
  70          $course = $this->getDataGenerator()->create_course(array('category' => 1, 'shortname' => 'ANON'));
  71          $this->assertNotEmpty($course);
  72          $page = $this->getDataGenerator()->create_module('page', array('course' => $course->id));
  73          $this->assertNotEmpty($page);
  74  
  75          // Create default group.
  76          $group = new \stdClass();
  77          $group->courseid = $course->id;
  78          $group->name = 'ANON';
  79          $group->id = $DB->insert_record('groups', $group);
  80  
  81          // Create default user.
  82          $user = $this->getDataGenerator()->create_user(array(
  83                  'username' => 'testuser',
  84                  'firstname' => 'Jimmy',
  85                  'lastname' => 'Kinnon'
  86          ));
  87  
  88          // Create default tag.
  89          $tag = $this->getDataGenerator()->create_tag(array('userid' => $user->id,
  90              'rawname' => 'Testtagname', 'isstandard' => 1));
  91  
  92          // Create default post.
  93          $post = new \stdClass();
  94          $post->userid = $user->id;
  95          $post->groupid = $group->id;
  96          $post->content = 'test post content text';
  97          $post->module = 'blog';
  98          $post->id = $DB->insert_record('post', $post);
  99  
 100          // Grab important ids.
 101          $this->courseid = $course->id;
 102          $this->cmid = $page->cmid;
 103          $this->groupid  = $group->id;
 104          $this->userid  = $user->id;
 105          $this->tagid  = $tag->id;
 106          $this->postid = $post->id;
 107      }
 108  
 109      /**
 110       * Test various blog related events.
 111       */
 112      public function test_blog_entry_created_event() {
 113          global $USER;
 114  
 115          $this->setAdminUser();
 116          $this->resetAfterTest();
 117  
 118          // Create a blog entry for another user as Admin.
 119          $sink = $this->redirectEvents();
 120          $blog = new \blog_entry();
 121          $blog->subject = "Subject of blog";
 122          $blog->userid = $this->userid;
 123          $states = \blog_entry::get_applicable_publish_states();
 124          $blog->publishstate = reset($states);
 125          $blog->add();
 126          $events = $sink->get_events();
 127          $sink->close();
 128          $event = reset($events);
 129          $sitecontext = \context_system::instance();
 130  
 131          // Validate event data.
 132          $this->assertInstanceOf('\core\event\blog_entry_created', $event);
 133          $url = new \moodle_url('/blog/index.php', array('entryid' => $event->objectid));
 134          $this->assertEquals($url, $event->get_url());
 135          $this->assertEquals($sitecontext->id, $event->contextid);
 136          $this->assertEquals($blog->id, $event->objectid);
 137          $this->assertEquals($USER->id, $event->userid);
 138          $this->assertEquals($this->userid, $event->relateduserid);
 139          $this->assertEquals("post", $event->objecttable);
 140          $arr = array(SITEID, 'blog', 'add', 'index.php?userid=' . $this->userid . '&entryid=' . $blog->id, $blog->subject);
 141          $this->assertEventLegacyLogData($arr, $event);
 142          $this->assertEquals("blog_entry_added", $event->get_legacy_eventname());
 143          $this->assertEventLegacyData($blog, $event);
 144          $this->assertEventContextNotUsed($event);
 145      }
 146  
 147      /**
 148       * Tests for event blog_entry_updated.
 149       */
 150      public function test_blog_entry_updated_event() {
 151          global $USER;
 152  
 153          $this->setAdminUser();
 154          $this->resetAfterTest();
 155          $sitecontext = \context_system::instance();
 156  
 157          // Edit a blog entry as Admin.
 158          $blog = new \blog_entry($this->postid);
 159          $sink = $this->redirectEvents();
 160          $blog->summary_editor = array('text' => 'Something', 'format' => FORMAT_MOODLE);
 161          $blog->edit(array(), null, array(), array());
 162          $events = $sink->get_events();
 163          $event = array_pop($events);
 164          $sink->close();
 165  
 166          // Validate event data.
 167          $this->assertInstanceOf('\core\event\blog_entry_updated', $event);
 168          $url = new \moodle_url('/blog/index.php', array('entryid' => $event->objectid));
 169          $this->assertEquals($url, $event->get_url());
 170          $this->assertEquals($sitecontext->id, $event->contextid);
 171          $this->assertEquals($blog->id, $event->objectid);
 172          $this->assertEquals($USER->id, $event->userid);
 173          $this->assertEquals($this->userid, $event->relateduserid);
 174          $this->assertEquals("post", $event->objecttable);
 175          $this->assertEquals("blog_entry_edited", $event->get_legacy_eventname());
 176          $this->assertEventLegacyData($blog, $event);
 177          $arr = array (SITEID, 'blog', 'update', 'index.php?userid=' . $this->userid . '&entryid=' . $blog->id, $blog->subject);
 178          $this->assertEventLegacyLogData($arr, $event);
 179          $this->assertEventContextNotUsed($event);
 180      }
 181  
 182      /**
 183       * Tests for event blog_entry_deleted.
 184       */
 185      public function test_blog_entry_deleted_event() {
 186          global $USER, $DB;
 187  
 188          $this->setAdminUser();
 189          $this->resetAfterTest();
 190          $sitecontext = \context_system::instance();
 191  
 192          // Delete a user blog entry as Admin.
 193          $blog = new \blog_entry($this->postid);
 194          $sink = $this->redirectEvents();
 195          $record = $DB->get_record('post', array('id' => $blog->id));
 196          $blog->delete();
 197          $events = $sink->get_events();
 198          $event = array_pop($events);
 199          $sink->close();
 200  
 201          // Validate event data.
 202          $this->assertInstanceOf('\core\event\blog_entry_deleted', $event);
 203          $this->assertEquals(null, $event->get_url());
 204          $this->assertEquals($sitecontext->id, $event->contextid);
 205          $this->assertEquals($blog->id, $event->objectid);
 206          $this->assertEquals($USER->id, $event->userid);
 207          $this->assertEquals($this->userid, $event->relateduserid);
 208          $this->assertEquals("post", $event->objecttable);
 209          $this->assertEquals($record, $event->get_record_snapshot("post", $blog->id));
 210          $this->assertSame('blog_entry_deleted', $event->get_legacy_eventname());
 211          $arr = array(SITEID, 'blog', 'delete', 'index.php?userid=' . $blog->userid, 'deleted blog entry with entry id# ' .
 212                  $blog->id);
 213          $this->assertEventLegacyLogData($arr, $event);
 214          $this->assertEventLegacyData($blog, $event);
 215          $this->assertEventContextNotUsed($event);
 216      }
 217  
 218      /**
 219       * Tests for event blog_association_deleted.
 220       */
 221      public function test_blog_association_deleted_event() {
 222          global $USER;
 223  
 224          $this->setAdminUser();
 225          $this->resetAfterTest();
 226          $sitecontext = \context_system::instance();
 227          $coursecontext = \context_course::instance($this->courseid);
 228          $contextmodule = \context_module::instance($this->cmid);
 229  
 230          // Add blog associations with a course.
 231          $blog = new \blog_entry($this->postid);
 232          $blog->add_association($coursecontext->id);
 233  
 234          $sink = $this->redirectEvents();
 235          $blog->remove_associations();
 236          $events = $sink->get_events();
 237          $event = reset($events);
 238          $sink->close();
 239  
 240          // Validate event data.
 241          $this->assertInstanceOf('\core\event\blog_association_deleted', $event);
 242          $this->assertEquals($sitecontext->id, $event->contextid);
 243          $this->assertEquals($blog->id, $event->other['blogid']);
 244          $this->assertEquals($USER->id, $event->userid);
 245          $this->assertEquals($this->userid, $event->relateduserid);
 246          $this->assertEquals('blog_association', $event->objecttable);
 247  
 248          // Add blog associations with a module.
 249          $blog = new \blog_entry($this->postid);
 250          $blog->add_association($contextmodule->id);
 251          $sink = $this->redirectEvents();
 252          $blog->remove_associations();
 253          $events = $sink->get_events();
 254          $event = reset($events);
 255          $sink->close();
 256  
 257          // Validate event data.
 258          $this->assertEquals($blog->id, $event->other['blogid']);
 259          $this->assertEquals($USER->id, $event->userid);
 260          $this->assertEventContextNotUsed($event);
 261      }
 262  
 263      /**
 264       * Tests for event blog_association_created.
 265       */
 266      public function test_blog_association_created_event() {
 267          global $USER;
 268  
 269          $this->setAdminUser();
 270          $this->resetAfterTest();
 271          $sitecontext = \context_system::instance();
 272          $coursecontext = \context_course::instance($this->courseid);
 273          $contextmodule = \context_module::instance($this->cmid);
 274  
 275          // Add blog associations with a course.
 276          $blog = new \blog_entry($this->postid);
 277          $sink = $this->redirectEvents();
 278          $blog->add_association($coursecontext->id);
 279          $events = $sink->get_events();
 280          $event = reset($events);
 281          $sink->close();
 282  
 283          // Validate event data.
 284          $this->assertInstanceOf('\core\event\blog_association_created', $event);
 285          $this->assertEquals($sitecontext->id, $event->contextid);
 286          $url = new \moodle_url('/blog/index.php', array('entryid' => $event->other['blogid']));
 287          $this->assertEquals($url, $event->get_url());
 288          $this->assertEquals($blog->id, $event->other['blogid']);
 289          $this->assertEquals($this->courseid, $event->other['associateid']);
 290          $this->assertEquals('course', $event->other['associatetype']);
 291          $this->assertEquals($blog->subject, $event->other['subject']);
 292          $this->assertEquals($USER->id, $event->userid);
 293          $this->assertEquals($this->userid, $event->relateduserid);
 294          $this->assertEquals('blog_association', $event->objecttable);
 295          $arr = array(SITEID, 'blog', 'add association', 'index.php?userid=' . $this->userid . '&entryid=' . $blog->id,
 296                       $blog->subject, 0, $this->userid);
 297          $this->assertEventLegacyLogData($arr, $event);
 298  
 299          // Add blog associations with a module.
 300          $blog = new \blog_entry($this->postid);
 301          $sink = $this->redirectEvents();
 302          $blog->add_association($contextmodule->id);
 303          $events = $sink->get_events();
 304          $event = reset($events);
 305          $sink->close();
 306  
 307          // Validate event data.
 308          $this->assertEquals($blog->id, $event->other['blogid']);
 309          $this->assertEquals($this->cmid, $event->other['associateid']);
 310          $this->assertEquals('coursemodule', $event->other['associatetype']);
 311          $arr = array(SITEID, 'blog', 'add association', 'index.php?userid=' . $this->userid . '&entryid=' . $blog->id,
 312                       $blog->subject, $this->cmid, $this->userid);
 313          $this->assertEventLegacyLogData($arr, $event);
 314          $this->assertEventContextNotUsed($event);
 315      }
 316  
 317      /**
 318       * Tests for event blog_association_created validations.
 319       */
 320      public function test_blog_association_created_event_validations() {
 321  
 322          $this->resetAfterTest();
 323  
 324           // Make sure associatetype validations work.
 325          try {
 326              \core\event\blog_association_created::create(array(
 327                  'contextid' => 1,
 328                  'objectid' => 3,
 329                  'relateduserid' => 2,
 330                  'other' => array('associateid' => 2 , 'blogid' => 3, 'subject' => 'blog subject')));
 331          } catch (\coding_exception $e) {
 332              $this->assertStringContainsString('The \'associatetype\' value must be set in other and be a valid type.', $e->getMessage());
 333          }
 334          try {
 335              \core\event\blog_association_created::create(array(
 336                  'contextid' => 1,
 337                  'objectid' => 3,
 338                  'relateduserid' => 2,
 339                  'other' => array('associateid' => 2 , 'blogid' => 3, 'associatetype' => 'random', 'subject' => 'blog subject')));
 340          } catch (\coding_exception $e) {
 341              $this->assertStringContainsString('The \'associatetype\' value must be set in other and be a valid type.', $e->getMessage());
 342          }
 343          // Make sure associateid validations work.
 344          try {
 345              \core\event\blog_association_created::create(array(
 346                  'contextid' => 1,
 347                  'objectid' => 3,
 348                  'relateduserid' => 2,
 349                  'other' => array('blogid' => 3, 'associatetype' => 'course', 'subject' => 'blog subject')));
 350          } catch (\coding_exception $e) {
 351              $this->assertStringContainsString('The \'associateid\' value must be set in other.', $e->getMessage());
 352          }
 353          // Make sure blogid validations work.
 354          try {
 355              \core\event\blog_association_created::create(array(
 356                  'contextid' => 1,
 357                  'objectid' => 3,
 358                  'relateduserid' => 2,
 359                  'other' => array('associateid' => 3, 'associatetype' => 'course', 'subject' => 'blog subject')));
 360          } catch (\coding_exception $e) {
 361              $this->assertStringContainsString('The \'blogid\' value must be set in other.', $e->getMessage());
 362          }
 363          // Make sure blogid validations work.
 364          try {
 365              \core\event\blog_association_created::create(array(
 366                  'contextid' => 1,
 367                  'objectid' => 3,
 368                  'relateduserid' => 2,
 369                  'other' => array('blogid' => 3, 'associateid' => 3, 'associatetype' => 'course')));
 370          } catch (\coding_exception $e) {
 371              $this->assertStringContainsString('The \'subject\' value must be set in other.', $e->getMessage());
 372          }
 373      }
 374  
 375      /**
 376       * Tests for event blog_entries_viewed.
 377       */
 378      public function test_blog_entries_viewed_event() {
 379  
 380          $this->setAdminUser();
 381  
 382          $other = array('entryid' => $this->postid, 'tagid' => $this->tagid, 'userid' => $this->userid, 'modid' => $this->cmid,
 383                         'groupid' => $this->groupid, 'courseid' => $this->courseid, 'search' => 'search', 'fromstart' => 2);
 384  
 385          // Trigger event.
 386          $sink = $this->redirectEvents();
 387          $eventparams = array('other' => $other);
 388          $eventinst = \core\event\blog_entries_viewed::create($eventparams);
 389          $eventinst->trigger();
 390          $events = $sink->get_events();
 391          $event = reset($events);
 392          $sink->close();
 393  
 394          // Validate event data.
 395          $url = new \moodle_url('/blog/index.php', $other);
 396          $url2 = new \moodle_url('index.php', $other);
 397          $this->assertEquals($url, $event->get_url());
 398          $arr = array(SITEID, 'blog', 'view', $url2->out(), 'view blog entry');
 399          $this->assertEventLegacyLogData($arr, $event);
 400          $this->assertEventContextNotUsed($event);
 401      }
 402  
 403      /**
 404       * Test comment_created event.
 405       */
 406      public function test_blog_comment_created_event() {
 407          global $USER, $CFG;
 408  
 409          $this->setAdminUser();
 410  
 411          require_once($CFG->dirroot . '/comment/lib.php');
 412          $context = \context_user::instance($USER->id);
 413  
 414          $cmt = new \stdClass();
 415          $cmt->context = $context;
 416          $cmt->courseid = $this->courseid;
 417          $cmt->area = 'format_blog';
 418          $cmt->itemid = $this->postid;
 419          $cmt->showcount = 1;
 420          $cmt->component = 'blog';
 421          $manager = new \comment($cmt);
 422  
 423          // Triggering and capturing the event.
 424          $sink = $this->redirectEvents();
 425          $manager->add("New comment");
 426          $events = $sink->get_events();
 427          $this->assertCount(1, $events);
 428          $event = reset($events);
 429  
 430          // Checking that the event contains the expected values.
 431          $this->assertInstanceOf('\core\event\blog_comment_created', $event);
 432          $this->assertEquals($context, $event->get_context());
 433          $this->assertEquals($this->postid, $event->other['itemid']);
 434          $url = new \moodle_url('/blog/index.php', array('entryid' => $this->postid));
 435          $this->assertEquals($url, $event->get_url());
 436          $this->assertEventContextNotUsed($event);
 437      }
 438  
 439      /**
 440       * Test comment_deleted event.
 441       */
 442      public function test_blog_comment_deleted_event() {
 443          global $USER, $CFG;
 444  
 445          $this->setAdminUser();
 446  
 447          require_once($CFG->dirroot . '/comment/lib.php');
 448          $context = \context_user::instance($USER->id);
 449  
 450          $cmt = new \stdClass();
 451          $cmt->context = $context;
 452          $cmt->courseid = $this->courseid;
 453          $cmt->area = 'format_blog';
 454          $cmt->itemid = $this->postid;
 455          $cmt->showcount = 1;
 456          $cmt->component = 'blog';
 457          $manager = new \comment($cmt);
 458          $newcomment = $manager->add("New comment");
 459  
 460          // Triggering and capturing the event.
 461          $sink = $this->redirectEvents();
 462          $manager->delete($newcomment->id);
 463          $events = $sink->get_events();
 464          $this->assertCount(1, $events);
 465          $event = reset($events);
 466  
 467          // Checking that the event contains the expected values.
 468          $this->assertInstanceOf('\core\event\blog_comment_deleted', $event);
 469          $this->assertEquals($context, $event->get_context());
 470          $this->assertEquals($this->postid, $event->other['itemid']);
 471          $url = new \moodle_url('/blog/index.php', array('entryid' => $this->postid));
 472          $this->assertEquals($url, $event->get_url());
 473          $this->assertEventContextNotUsed($event);
 474      }
 475  
 476      /**
 477       * Test external blog added event.
 478       *
 479       * There is no external API for this, so the unit test will simply
 480       * create and trigger the event and ensure data is returned as expected.
 481       */
 482      public function test_external_blog_added_event() {
 483  
 484          // Trigger an event: external blog added.
 485          $eventparams = array(
 486              'context' => $context = \context_system::instance(),
 487              'objectid' => 1001,
 488              'other' => array('url' => 'http://moodle.org')
 489          );
 490  
 491          $event = \core\event\blog_external_added::create($eventparams);
 492          // Trigger and capture the event.
 493          $sink = $this->redirectEvents();
 494          $event->trigger();
 495          $events = $sink->get_events();
 496          $event = reset($events);
 497  
 498          // Check that the event data is valid.
 499          $this->assertInstanceOf('\core\event\blog_external_added', $event);
 500          $this->assertEquals(1001, $event->objectid);
 501          $this->assertEquals('http://moodle.org', $event->other['url']);
 502          $this->assertDebuggingNotCalled();
 503      }
 504  
 505      /**
 506       * Test external blog updated event.
 507       *
 508       * There is no external API for this, so the unit test will simply
 509       * create and trigger the event and ensure data is returned as expected.
 510       */
 511      public function test_external_blog_updated_event() {
 512  
 513          // Trigger an event: external blog updated.
 514          $eventparams = array(
 515              'context' => $context = \context_system::instance(),
 516              'objectid' => 1001,
 517              'other' => array('url' => 'http://moodle.org')
 518          );
 519  
 520          $event = \core\event\blog_external_updated::create($eventparams);
 521          // Trigger and capture the event.
 522          $sink = $this->redirectEvents();
 523          $event->trigger();
 524          $events = $sink->get_events();
 525          $event = reset($events);
 526  
 527          // Check that the event data is valid.
 528          $this->assertInstanceOf('\core\event\blog_external_updated', $event);
 529          $this->assertEquals(1001, $event->objectid);
 530          $this->assertEquals('http://moodle.org', $event->other['url']);
 531          $this->assertDebuggingNotCalled();
 532      }
 533  
 534      /**
 535       * Test external blog removed event.
 536       *
 537       * There is no external API for this, so the unit test will simply
 538       * create and trigger the event and ensure data is returned as expected.
 539       */
 540      public function test_external_blog_removed_event() {
 541  
 542          // Trigger an event: external blog removed.
 543          $eventparams = array(
 544              'context' => $context = \context_system::instance(),
 545              'objectid' => 1001,
 546          );
 547  
 548          $event = \core\event\blog_external_removed::create($eventparams);
 549          // Trigger and capture the event.
 550          $sink = $this->redirectEvents();
 551          $event->trigger();
 552          $events = $sink->get_events();
 553          $event = reset($events);
 554  
 555          // Check that the event data is valid.
 556          $this->assertInstanceOf('\core\event\blog_external_removed', $event);
 557          $this->assertEquals(1001, $event->objectid);
 558          $this->assertDebuggingNotCalled();
 559      }
 560  
 561      /**
 562       * Test external blogs viewed event.
 563       *
 564       * There is no external API for this, so the unit test will simply
 565       * create and trigger the event and ensure data is returned as expected.
 566       */
 567      public function test_external_blogs_viewed_event() {
 568  
 569          // Trigger an event: external blogs viewed.
 570          $eventparams = array(
 571              'context' => $context = \context_system::instance(),
 572          );
 573  
 574          $event = \core\event\blog_external_viewed::create($eventparams);
 575          // Trigger and capture the event.
 576          $sink = $this->redirectEvents();
 577          $event->trigger();
 578          $events = $sink->get_events();
 579          $event = reset($events);
 580  
 581          // Check that the event data is valid.
 582          $this->assertInstanceOf('\core\event\blog_external_viewed', $event);
 583          $this->assertDebuggingNotCalled();
 584      }
 585  }