Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

   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   * External comment functions unit tests
  19   *
  20   * @package    core_comment
  21   * @category   external
  22   * @copyright  2015 Juan Leyva <juan@moodle.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   * @since      Moodle 2.9
  25   */
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  global $CFG;
  30  
  31  require_once($CFG->dirroot . '/webservice/tests/helpers.php');
  32  
  33  /**
  34   * External comment functions unit tests
  35   *
  36   * @package    core_comment
  37   * @category   external
  38   * @copyright  2015 Juan Leyva <juan@moodle.com>
  39   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  40   * @since      Moodle 2.9
  41   */
  42  class core_comment_externallib_testcase extends externallib_advanced_testcase {
  43  
  44      /**
  45       * Tests set up
  46       */
  47      protected function setUp(): void {
  48          $this->resetAfterTest();
  49      }
  50  
  51      /**
  52       * Helper used to set up a course, with a module, a teacher and two students.
  53       *
  54       * @return array the array of records corresponding to the course, teacher, and students.
  55       */
  56      protected function setup_course_and_users_basic() {
  57          global $CFG, $DB;
  58  
  59          require_once($CFG->dirroot . '/comment/lib.php');
  60  
  61          $CFG->usecomments = true;
  62  
  63          $student1 = $this->getDataGenerator()->create_user();
  64          $student2 = $this->getDataGenerator()->create_user();
  65          $teacher1 = $this->getDataGenerator()->create_user();
  66          $course1 = $this->getDataGenerator()->create_course(array('enablecomment' => 1));
  67          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
  68          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
  69          $this->getDataGenerator()->enrol_user($student1->id, $course1->id, $studentrole->id);
  70          $this->getDataGenerator()->enrol_user($student2->id, $course1->id, $studentrole->id);
  71          $this->getDataGenerator()->enrol_user($teacher1->id, $course1->id, $teacherrole->id);
  72  
  73          // Create a database module instance.
  74          $record = new stdClass();
  75          $record->course = $course1->id;
  76          $record->name = "Mod data test";
  77          $record->intro = "Some intro of some sort";
  78          $record->comments = 1;
  79  
  80          $module1 = $this->getDataGenerator()->create_module('data', $record);
  81          $field = data_get_field_new('text', $module1);
  82  
  83          $fielddetail = new stdClass();
  84          $fielddetail->name = 'Name';
  85          $fielddetail->description = 'Some name';
  86  
  87          $field->define_field($fielddetail);
  88          $field->insert_field();
  89          $recordid = data_add_record($module1);
  90  
  91          $datacontent = array();
  92          $datacontent['fieldid'] = $field->field->id;
  93          $datacontent['recordid'] = $recordid;
  94          $datacontent['content'] = 'Asterix';
  95          $DB->insert_record('data_content', $datacontent);
  96  
  97          return [$module1, $recordid, $teacher1, $student1, $student2];
  98      }
  99  
 100      /**
 101       * Test get_comments
 102       */
 103      public function test_get_comments() {
 104          global $CFG;
 105          [$module1, $recordid, $teacher1, $student1, $student2] = $this->setup_course_and_users_basic();
 106  
 107          // Create some comments as student 1.
 108          $this->setUser($student1);
 109          $inputdata = [
 110              [
 111                  'contextlevel' => 'module',
 112                  'instanceid' => $module1->cmid,
 113                  'component' => 'mod_data',
 114                  'content' => 'abc',
 115                  'itemid' => $recordid,
 116                  'area' => 'database_entry'
 117              ],
 118              [
 119                  'contextlevel' => 'module',
 120                  'instanceid' => $module1->cmid,
 121                  'component' => 'mod_data',
 122                  'content' => 'def',
 123                  'itemid' => $recordid,
 124                  'area' => 'database_entry'
 125              ]
 126          ];
 127          $result = core_comment_external::add_comments($inputdata);
 128          $result = external_api::clean_returnvalue(core_comment_external::add_comments_returns(), $result);
 129          $ids = array_column($result, 'id');
 130  
 131          // Verify we can get the comments.
 132          $contextlevel = 'module';
 133          $instanceid = $module1->cmid;
 134          $component = 'mod_data';
 135          $itemid = $recordid;
 136          $area = 'database_entry';
 137          $page = 0;
 138          $result = core_comment_external::get_comments($contextlevel, $instanceid, $component, $itemid, $area, $page);
 139          $result = external_api::clean_returnvalue(core_comment_external::get_comments_returns(), $result);
 140  
 141          $this->assertCount(0, $result['warnings']);
 142          $this->assertCount(2, $result['comments']);
 143          $this->assertEquals(2, $result['count']);
 144          $this->assertEquals(15, $result['perpage']);
 145          $this->assertTrue($result['canpost']);
 146  
 147          $this->assertEquals($student1->id, $result['comments'][0]['userid']);
 148          $this->assertEquals($student1->id, $result['comments'][1]['userid']);
 149  
 150          $this->assertEquals($ids[1], $result['comments'][0]['id']); // Default ordering newer first.
 151          $this->assertEquals($ids[0], $result['comments'][1]['id']);
 152  
 153          // Test sort direction and pagination.
 154          $CFG->commentsperpage = 1;
 155          $result = core_comment_external::get_comments($contextlevel, $instanceid, $component, $itemid, $area, $page, 'ASC');
 156          $result = external_api::clean_returnvalue(core_comment_external::get_comments_returns(), $result);
 157  
 158          $this->assertCount(0, $result['warnings']);
 159          $this->assertCount(1, $result['comments']); // Only one per page.
 160          $this->assertEquals(2, $result['count']);
 161          $this->assertEquals($CFG->commentsperpage, $result['perpage']);
 162          $this->assertEquals($ids[0], $result['comments'][0]['id']); // Comments order older first.
 163  
 164          // Next page.
 165          $result = core_comment_external::get_comments($contextlevel, $instanceid, $component, $itemid, $area, $page + 1, 'ASC');
 166          $result = external_api::clean_returnvalue(core_comment_external::get_comments_returns(), $result);
 167  
 168          $this->assertCount(0, $result['warnings']);
 169          $this->assertCount(1, $result['comments']);
 170          $this->assertEquals(2, $result['count']);
 171          $this->assertEquals($CFG->commentsperpage, $result['perpage']);
 172          $this->assertEquals($ids[1], $result['comments'][0]['id']);
 173      }
 174  
 175      /**
 176       * Test add_comments not enabled site level
 177       */
 178      public function test_add_comments_not_enabled_site_level() {
 179          global $CFG;
 180          [$module1, $recordid, $teacher1, $student1, $student2] = $this->setup_course_and_users_basic();
 181  
 182          // Try to add a comment, as student 1, when comments is disabled at site level.
 183          $this->setUser($student1);
 184          $CFG->usecomments = false;
 185  
 186          $this->expectException(comment_exception::class);
 187          core_comment_external::add_comments([
 188              [
 189                  'contextlevel' => 'module',
 190                  'instanceid' => $module1->cmid,
 191                  'component' => 'mod_data',
 192                  'content' => 'abc',
 193                  'itemid' => $recordid,
 194                  'area' => 'database_entry'
 195              ]
 196          ]);
 197      }
 198  
 199      /**
 200       * Test add_comments not enabled module level
 201       */
 202      public function test_add_comments_not_enabled_module_level() {
 203          global $DB;
 204          [$module1, $recordid, $teacher1, $student1, $student2] = $this->setup_course_and_users_basic();
 205  
 206          // Disable comments for the module.
 207          $DB->set_field('data', 'comments', 0, array('id' => $module1->id));
 208  
 209          // Verify we can't add a comment.
 210          $this->setUser($student1);
 211          $this->expectException(comment_exception::class);
 212          core_comment_external::add_comments([
 213              [
 214                  'contextlevel' => 'module',
 215                  'instanceid' => $module1->cmid,
 216                  'component' => 'mod_data',
 217                  'content' => 'abc',
 218                  'itemid' => $recordid,
 219                  'area' => 'database_entry'
 220              ]
 221          ]);
 222      }
 223  
 224      /**
 225       * Test add_comments
 226       */
 227      public function test_add_comments_single() {
 228          [$module1, $recordid, $teacher1, $student1, $student2] = $this->setup_course_and_users_basic();
 229  
 230          // Add a comment as student 1.
 231          $this->setUser($student1);
 232          $result = core_comment_external::add_comments([
 233              [
 234                  'contextlevel' => 'module',
 235                  'instanceid' => $module1->cmid,
 236                  'component' => 'mod_data',
 237                  'content' => 'abc',
 238                  'itemid' => $recordid,
 239                  'area' => 'database_entry'
 240              ]
 241          ]);
 242          $result = external_api::clean_returnvalue(core_comment_external::add_comments_returns(), $result);
 243  
 244          // Verify the result contains 1 result having the correct structure.
 245          $this->assertCount(1, $result);
 246  
 247          $expectedkeys = [
 248              'id',
 249              'content',
 250              'format',
 251              'timecreated',
 252              'strftimeformat',
 253              'profileurl',
 254              'fullname',
 255              'time',
 256              'avatar',
 257              'userid',
 258              'delete',
 259          ];
 260          foreach ($expectedkeys as $key) {
 261              $this->assertArrayHasKey($key, $result[0]);
 262          }
 263      }
 264  
 265      /**
 266       * Test add_comments when one of the comments contains invalid data and cannot be created.
 267       *
 268       * This simply verifies that the entire operation fails.
 269       */
 270      public function test_add_comments_multiple_contains_invalid() {
 271          [$module1, $recordid, $teacher1, $student1, $student2] = $this->setup_course_and_users_basic();
 272  
 273          // Try to create some comments as student 1, but provide a bad area for the second comment.
 274          $this->setUser($student1);
 275          $this->expectException(comment_exception::class);
 276          core_comment_external::add_comments([
 277              [
 278                  'contextlevel' => 'module',
 279                  'instanceid' => $module1->cmid,
 280                  'component' => 'mod_data',
 281                  'content' => 'abc',
 282                  'itemid' => $recordid,
 283                  'area' => 'database_entry'
 284              ],
 285              [
 286                  'contextlevel' => 'module',
 287                  'instanceid' => $module1->cmid,
 288                  'component' => 'mod_data',
 289                  'content' => 'def',
 290                  'itemid' => $recordid,
 291                  'area' => 'badarea'
 292              ],
 293          ]);
 294      }
 295  
 296      /**
 297       * Test add_comments when one of the comments contains invalid data and cannot be created.
 298       *
 299       * This simply verifies that the entire operation fails.
 300       */
 301      public function test_add_comments_multiple_all_valid() {
 302          [$module1, $recordid, $teacher1, $student1, $student2] = $this->setup_course_and_users_basic();
 303  
 304          // Try to create some comments as student 1.
 305          $this->setUser($student1);
 306          $inputdata = [
 307              [
 308                  'contextlevel' => 'module',
 309                  'instanceid' => $module1->cmid,
 310                  'component' => 'mod_data',
 311                  'content' => 'abc',
 312                  'itemid' => $recordid,
 313                  'area' => 'database_entry'
 314              ],
 315              [
 316                  'contextlevel' => 'module',
 317                  'instanceid' => $module1->cmid,
 318                  'component' => 'mod_data',
 319                  'content' => 'def',
 320                  'itemid' => $recordid,
 321                  'area' => 'database_entry'
 322              ]
 323          ];
 324          $result = core_comment_external::add_comments($inputdata);
 325          $result = external_api::clean_returnvalue(core_comment_external::add_comments_returns(), $result);
 326  
 327          // Two comments should have been created.
 328          $this->assertCount(2, $result);
 329  
 330          // The content for each comment should come back formatted.
 331          foreach ($result as $index => $comment) {
 332              $formatoptions = array('overflowdiv' => true, 'blanktarget' => true);
 333              $expectedcontent = format_text($inputdata[$index]['content'], FORMAT_MOODLE, $formatoptions);
 334              $this->assertEquals($expectedcontent, $comment['content']);
 335          }
 336      }
 337  
 338      /**
 339       * Test add_comments invalid area
 340       */
 341      public function test_add_comments_invalid_area() {
 342          [$module1, $recordid, $teacher1, $student1, $student2] = $this->setup_course_and_users_basic();
 343  
 344          // Try to create a comment with an invalid area, verifying failure.
 345          $this->setUser($student1);
 346          $comments = [
 347              [
 348                  'contextlevel' => 'module',
 349                  'instanceid' => $module1->cmid,
 350                  'component' => 'mod_data',
 351                  'content' => 'abc',
 352                  'itemid' => $recordid,
 353                  'area' => 'spaghetti'
 354              ]
 355          ];
 356          $this->expectException(comment_exception::class);
 357          core_comment_external::add_comments($comments);
 358      }
 359  
 360      /**
 361       * Test delete_comment invalid comment.
 362       */
 363      public function test_delete_comments_invalid_comment_id() {
 364          [$module1, $recordid, $teacher1, $student1, $student2] = $this->setup_course_and_users_basic();
 365          $this->setUser($student1);
 366  
 367          $this->expectException(comment_exception::class);
 368          core_comment_external::delete_comments([-1, 0]);
 369      }
 370  
 371      /**
 372       * Test delete_comment own user.
 373       */
 374      public function test_delete_comments_own_user() {
 375          [$module1, $recordid, $teacher1, $student1, $student2] = $this->setup_course_and_users_basic();
 376  
 377          // Create a few comments as student 1.
 378          $this->setUser($student1);
 379          $result = core_comment_external::add_comments([
 380              [
 381                  'contextlevel' => 'module',
 382                  'instanceid' => $module1->cmid,
 383                  'component' => 'mod_data',
 384                  'content' => 'abc',
 385                  'itemid' => $recordid,
 386                  'area' => 'database_entry'
 387              ],
 388              [
 389                  'contextlevel' => 'module',
 390                  'instanceid' => $module1->cmid,
 391                  'component' => 'mod_data',
 392                  'content' => 'def',
 393                  'itemid' => $recordid,
 394                  'area' => 'database_entry'
 395              ]
 396          ]);
 397          $result = external_api::clean_returnvalue(core_comment_external::add_comments_returns(), $result);
 398  
 399          // Delete those comments we just created.
 400          $result = core_comment_external::delete_comments([
 401              $result[0]['id'],
 402              $result[1]['id']
 403          ]);
 404          $result = external_api::clean_returnvalue(core_comment_external::delete_comments_returns(), $result);
 405          $this->assertEquals([], $result);
 406      }
 407  
 408      /**
 409       * Test delete_comment other student.
 410       */
 411      public function test_delete_comment_other_student() {
 412          [$module1, $recordid, $teacher1, $student1, $student2] = $this->setup_course_and_users_basic();
 413  
 414          // Create a comment as the student.
 415          $this->setUser($student1);
 416          $result = core_comment_external::add_comments([
 417              [
 418                  'contextlevel' => 'module',
 419                  'instanceid' => $module1->cmid,
 420                  'component' => 'mod_data',
 421                  'content' => 'abc',
 422                  'itemid' => $recordid,
 423                  'area' => 'database_entry'
 424              ]
 425          ]);
 426          $result = external_api::clean_returnvalue(core_comment_external::add_comments_returns(), $result);
 427  
 428          // Now, as student 2, try to delete the comment made by student 1. Verify we can't.
 429          $this->setUser($student2);
 430          $this->expectException(comment_exception::class);
 431          core_comment_external::delete_comments([$result[0]['id']]);
 432      }
 433  
 434      /**
 435       * Test delete_comment as teacher.
 436       */
 437      public function test_delete_comments_as_teacher() {
 438          [$module1, $recordid, $teacher1, $student1, $student2] = $this->setup_course_and_users_basic();
 439  
 440          // Create a comment as the student.
 441          $this->setUser($student1);
 442          $result = core_comment_external::add_comments([
 443              [
 444                  'contextlevel' => 'module',
 445                  'instanceid' => $module1->cmid,
 446                  'component' => 'mod_data',
 447                  'content' => 'abc',
 448                  'itemid' => $recordid,
 449                  'area' => 'database_entry'
 450              ]
 451          ]);
 452          $result = external_api::clean_returnvalue(core_comment_external::add_comments_returns(), $result);
 453  
 454          // Verify teachers can delete the comment.
 455          $this->setUser($teacher1);
 456          $result = core_comment_external::delete_comments([$result[0]['id']]);
 457          $result = external_api::clean_returnvalue(core_comment_external::delete_comments_returns(), $result);
 458          $this->assertEquals([], $result);
 459      }
 460  }