Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [Versions 401 and 402]

   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  namespace mod_data;
  18  
  19  use context_module;
  20  use rating_manager;
  21  use stdClass;
  22  
  23  /**
  24   * Template tests class for mod_data.
  25   *
  26   * @package    mod_data
  27   * @category   test
  28   * @copyright  2022 Ferran Recio <ferran@moodle.com>
  29   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  30   * @coversDefaultClass \mod_data\template
  31   */
  32  class template_test extends \advanced_testcase {
  33      /**
  34       * Setup to ensure that fixtures are loaded.
  35       */
  36      public static function setupBeforeClass(): void {
  37          global $CFG;
  38          require_once($CFG->dirroot . '/rating/lib.php');
  39      }
  40  
  41      /**
  42       * Test for static create methods.
  43       *
  44       * @covers ::parse_entries
  45       * @dataProvider parse_entries_provider
  46       * @param string $templatecontent the template string
  47       * @param string $expected expected output
  48       * @param string $rolename the user rolename
  49       * @param bool $enableexport is portfolio export is enabled
  50       * @param bool $approved if the entry is approved
  51       * @param bool $enablecomments is comments are enabled
  52       * @param bool $enableratings if ratings are enabled
  53       * @param array $options extra parser options
  54       * @param bool $otherauthor if the entry is from another user
  55       */
  56      public function test_parse_entries(
  57          string $templatecontent,
  58          string $expected,
  59          string $rolename = 'editingteacher',
  60          bool $enableexport = false,
  61          bool $approved = true,
  62          bool $enablecomments = false,
  63          bool $enableratings = false,
  64          array $options = [],
  65          bool $otherauthor = false
  66      ) {
  67          global $DB, $PAGE;
  68          // Comments, tags, approval, user role.
  69          $this->resetAfterTest();
  70  
  71          $params = ['approval' => true];
  72  
  73          // Enable comments.
  74          if ($enablecomments) {
  75              set_config('usecomments', 1);
  76              $params['comments'] = true;
  77              $PAGE->reset_theme_and_output();
  78              $PAGE->set_url('/mod/data/view.php');
  79          }
  80  
  81          $course = $this->getDataGenerator()->create_course();
  82          $params['course'] = $course;
  83          $activity = $this->getDataGenerator()->create_module('data', $params);
  84          $cm = get_coursemodule_from_id('data', $activity->cmid, 0, false, MUST_EXIST);
  85          $context = context_module::instance($cm->id);
  86  
  87          $user = $this->getDataGenerator()->create_user();
  88          $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
  89          $this->getDataGenerator()->enrol_user($user->id, $course->id, $roleids[$rolename]);
  90          $author = $user;
  91  
  92          if ($otherauthor) {
  93              $user2 = $this->getDataGenerator()->create_user();
  94              $this->getDataGenerator()->enrol_user($user2->id, $course->id, $roleids[$rolename]);
  95              $author = $user2;
  96          }
  97  
  98          // Generate an entry.
  99          $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 100          $fieldrecord = (object)['name' => 'myfield', 'type' => 'text'];
 101          $field = $generator->create_field($fieldrecord, $activity);
 102          $otherfieldrecord = (object)['name' => 'otherfield', 'type' => 'text'];
 103          $otherfield = $generator->create_field($otherfieldrecord, $activity);
 104  
 105          $this->setUser($user);
 106  
 107          $entryid = $generator->create_entry(
 108              $activity,
 109              [
 110                  $field->field->id => 'Example entry',
 111                  $otherfield->field->id => 'Another example',
 112              ],
 113              0,
 114              ['Cats', 'Dogs'],
 115              ['approved' => $approved]
 116          );
 117  
 118          if ($enableexport) {
 119              $this->enable_portfolio($user);
 120          }
 121  
 122          $manager = manager::create_from_instance($activity);
 123  
 124          $entry = (object)[
 125              'id' => $entryid,
 126              'approved' => $approved,
 127              'timecreated' => 1657618639,
 128              'timemodified' => 1657618650,
 129              'userid' => $author->id,
 130              'groupid' => 0,
 131              'dataid' => $activity->id,
 132              'picture' => 0,
 133              'firstname' => $author->firstname,
 134              'lastname' => $author->lastname,
 135              'firstnamephonetic' => $author->firstnamephonetic,
 136              'lastnamephonetic' => $author->lastnamephonetic,
 137              'middlename' => $author->middlename,
 138              'alternatename' => $author->alternatename,
 139              'imagealt' => 'PIXEXAMPLE',
 140              'email' => $author->email,
 141          ];
 142          $entries = [$entry];
 143  
 144          if ($enableratings) {
 145              $entries = $this->enable_ratings($context, $activity, $entries, $user);
 146          }
 147  
 148          // Some cooked variables for the regular expression.
 149          $replace = [
 150              '{authorfullname}' => fullname($author),
 151              '{timeadded}' => userdate($entry->timecreated, get_string('strftimedatemonthabbr', 'langconfig')),
 152              '{timemodified}' => userdate($entry->timemodified, get_string('strftimedatemonthabbr', 'langconfig')),
 153              '{fieldid}' => $field->field->id,
 154              '{fieldname}' => $field->field->name,
 155              '{fielddescription}' => $field->field->description,
 156              '{entryid}' => $entry->id,
 157              '{cmid}' => $cm->id,
 158              '{courseid}' => $course->id,
 159              '{authorid}' => $author->id
 160          ];
 161  
 162          $parser = new template($manager, $templatecontent, $options);
 163          $result = $parser->parse_entries($entries);
 164  
 165          // We don't want line breaks for the validations.
 166          $result = str_replace("\n", '', $result);
 167          $regexp = str_replace(array_keys($replace), array_values($replace), $expected);
 168          $this->assertMatchesRegularExpression($regexp, $result);
 169      }
 170  
 171      /**
 172       * Data provider for test_parse_entries().
 173       *
 174       * @return array of scenarios
 175       */
 176      public function parse_entries_provider(): array {
 177          return [
 178              // Teacher scenarios.
 179              'Teacher id tag' => [
 180                  'templatecontent' => 'Some ##id## tag',
 181                  'expected' => '|Some {entryid} tag|',
 182                  'rolename' => 'editingteacher',
 183              ],
 184              'Teacher delete tag' => [
 185                  'templatecontent' => 'Some ##delete## tag',
 186                  'expected' => '|Some .*delete.*{entryid}.*sesskey.*Delete.* tag|',
 187                  'rolename' => 'editingteacher',
 188              ],
 189              'Teacher edit tag' => [
 190                  'templatecontent' => 'Some ##edit## tag',
 191                  'expected' => '|Some .*edit.*{entryid}.*sesskey.*Edit.* tag|',
 192                  'rolename' => 'editingteacher',
 193              ],
 194              'Teacher more tag' => [
 195                  'templatecontent' => 'Some ##more## tag',
 196                  'expected' => '|Some .*more.*{cmid}.*rid.*{entryid}.*More.* tag|',
 197                  'rolename' => 'editingteacher',
 198                  'enableexport' => false,
 199                  'approved' => true,
 200                  'enablecomments' => false,
 201                  'enableratings' => false,
 202                  'options' => ['showmore' => true],
 203              ],
 204              'Teacher more tag with showmore set to false' => [
 205                  'templatecontent' => 'Some ##more## tag',
 206                  'expected' => '|Some  tag|',
 207                  'rolename' => 'editingteacher',
 208                  'enableexport' => false,
 209                  'approved' => true,
 210                  'enablecomments' => false,
 211                  'enableratings' => false,
 212                  'options' => ['showmore' => false],
 213              ],
 214              'Teacher moreurl tag' => [
 215                  'templatecontent' => 'Some ##moreurl## tag',
 216                  'expected' => '|Some .*/mod/data/view.*{cmid}.*rid.*{entryid}.* tag|',
 217                  'rolename' => 'editingteacher',
 218                  'enableexport' => false,
 219                  'approved' => true,
 220                  'enablecomments' => false,
 221                  'enableratings' => false,
 222                  'options' => ['showmore' => true],
 223              ],
 224              'Teacher moreurl tag with showmore set to false' => [
 225                  'templatecontent' => 'Some ##moreurl## tag',
 226                  'expected' => '|Some .*/mod/data/view.*{cmid}.*rid.*{entryid}.* tag|',
 227                  'rolename' => 'editingteacher',
 228                  'enableexport' => false,
 229                  'approved' => true,
 230                  'enablecomments' => false,
 231                  'enableratings' => false,
 232                  'options' => ['showmore' => false],
 233              ],
 234              'Teacher delcheck tag' => [
 235                  'templatecontent' => 'Some ##delcheck## tag',
 236                  'expected' => '|Some .*input.*checkbox.*value.*{entryid}.* tag|',
 237                  'rolename' => 'editingteacher',
 238              ],
 239              'Teacher user tag' => [
 240                  'templatecontent' => 'Some ##user## tag',
 241                  'expected' => '|Some .*user/view.*{authorid}.*course.*{courseid}.*{authorfullname}.* tag|',
 242                  'rolename' => 'editingteacher',
 243              ],
 244              'Teacher userpicture tag' => [
 245                  'templatecontent' => 'Some ##userpicture## tag',
 246                  'expected' => '|Some .*user/view.*{authorid}.*course.*{courseid}.* tag|',
 247                  'rolename' => 'editingteacher',
 248              ],
 249              'Teacher export tag' => [
 250                  'templatecontent' => 'Some ##export## tag',
 251                  'expected' => '|Some .*portfolio/add.* tag|',
 252                  'rolename' => 'editingteacher',
 253                  'enableexport' => true,
 254              ],
 255              'Teacher export tag not configured' => [
 256                  'templatecontent' => 'Some ##export## tag',
 257                  'expected' => '|Some  tag|',
 258                  'rolename' => 'editingteacher',
 259                  'enableexport' => false,
 260              ],
 261              'Teacher timeadded tag' => [
 262                  'templatecontent' => 'Some ##timeadded## tag',
 263                  'expected' => '|Some <span.*>{timeadded}</span> tag|',
 264                  'rolename' => 'editingteacher',
 265              ],
 266              'Teacher timemodified tag' => [
 267                  'templatecontent' => 'Some ##timemodified## tag',
 268                  'expected' => '|Some <span.*>{timemodified}</span> tag|',
 269                  'rolename' => 'editingteacher',
 270              ],
 271              'Teacher approve tag approved entry' => [
 272                  'templatecontent' => 'Some ##approve## tag',
 273                  'expected' => '|Some  tag|',
 274                  'rolename' => 'editingteacher',
 275                  'enableexport' => false,
 276                  'approved' => true,
 277              ],
 278              'Teacher approve tag disapproved entry' => [
 279                  'templatecontent' => 'Some ##approve## tag',
 280                  'expected' => '|Some .*approve.*{entryid}.*sesskey.*Approve.* tag|',
 281                  'rolename' => 'editingteacher',
 282                  'enableexport' => false,
 283                  'approved' => false,
 284              ],
 285              'Teacher disapprove tag approved entry' => [
 286                  'templatecontent' => 'Some ##disapprove## tag',
 287                  'expected' => '|Some .*disapprove.*{entryid}.*sesskey.*Undo approval.* tag|',
 288                  'rolename' => 'editingteacher',
 289                  'enableexport' => false,
 290                  'approved' => true,
 291              ],
 292              'Teacher disapprove tag disapproved entry' => [
 293                  'templatecontent' => 'Some ##disapprove## tag',
 294                  'expected' => '|Some  tag|',
 295                  'rolename' => 'editingteacher',
 296                  'enableexport' => false,
 297                  'approved' => false,
 298              ],
 299              'Teacher approvalstatus tag approved entry' => [
 300                  'templatecontent' => 'Some ##approvalstatus## tag',
 301                  'expected' => '|Some  tag|', // We do not display the approval status anymore.
 302                  'rolename' => 'editingteacher',
 303                  'enableexport' => false,
 304                  'approved' => true,
 305              ],
 306              'Teacher approvalstatus tag disapproved entry' => [
 307                  'templatecontent' => 'Some ##approvalstatus## tag',
 308                  'expected' => '|Some .*Pending approval.* tag|',
 309                  'rolename' => 'editingteacher',
 310                  'enableexport' => false,
 311                  'approved' => false,
 312              ],
 313              'Teacher approvalstatusclass tag approved entry' => [
 314                  'templatecontent' => 'Some ##approvalstatusclass## tag',
 315                  'expected' => '|Some approved tag|',
 316                  'rolename' => 'editingteacher',
 317                  'enableexport' => false,
 318                  'approved' => true,
 319              ],
 320              'Teacher approvalstatusclass tag disapproved entry' => [
 321                  'templatecontent' => 'Some ##approvalstatusclass## tag',
 322                  'expected' => '|Some notapproved tag|',
 323                  'rolename' => 'editingteacher',
 324                  'enableexport' => false,
 325                  'approved' => false,
 326              ],
 327              'Teacher tags tag' => [
 328                  'templatecontent' => 'Some ##tags## tag',
 329                  'expected' => '|Some .*Cats.* tag|',
 330                  'rolename' => 'editingteacher',
 331              ],
 332              'Teacher field name tag' => [
 333                  'templatecontent' => 'Some [[myfield]] tag',
 334                  'expected' => '|Some .*Example entry.* tag|',
 335                  'rolename' => 'editingteacher',
 336              ],
 337              'Teacher field#id tag' => [
 338                  'templatecontent' => 'Some [[myfield#id]] tag',
 339                  'expected' => '|Some {fieldid} tag|',
 340                  'rolename' => 'editingteacher',
 341              ],
 342              'Teacher field#name tag' => [
 343                  'templatecontent' => 'Some [[myfield#name]] tag',
 344                  'expected' => '|Some {fieldname} tag|',
 345                  'rolename' => 'editingteacher',
 346              ],
 347              'Teacher field#description tag' => [
 348                  'templatecontent' => 'Some [[myfield#description]] tag',
 349                  'expected' => '|Some {fielddescription} tag|',
 350                  'rolename' => 'editingteacher',
 351              ],
 352              'Teacher comments name tag with comments enabled' => [
 353                  'templatecontent' => 'Some ##comments## tag',
 354                  'expected' => '|Some .*Comments.* tag|',
 355                  'rolename' => 'editingteacher',
 356                  'enableexport' => false,
 357                  'approved' => true,
 358                  'enablecomments' => true,
 359              ],
 360              'Teacher comments name tag with comments disabled' => [
 361                  'templatecontent' => 'Some ##comments## tag',
 362                  'expected' => '|Some  tag|',
 363                  'rolename' => 'editingteacher',
 364                  'enableexport' => false,
 365                  'approved' => true,
 366                  'enablecomments' => false,
 367              ],
 368              'Teacher comment forced with comments enables' => [
 369                  'templatecontent' => 'No tags',
 370                  'expected' => '|No tags.*Comments.*|',
 371                  'rolename' => 'editingteacher',
 372                  'enableexport' => false,
 373                  'approved' => true,
 374                  'enablecomments' => true,
 375                  'enableratings' => false,
 376                  'options' => ['comments' => true],
 377              ],
 378              'Teacher comment forced without comments enables' => [
 379                  'templatecontent' => 'No tags',
 380                  'expected' => '|^No tags$|',
 381                  'rolename' => 'editingteacher',
 382                  'enableexport' => false,
 383                  'approved' => true,
 384                  'enablecomments' => false,
 385                  'enableratings' => false,
 386                  'options' => ['comments' => true],
 387              ],
 388              'Teacher adding ratings without ratings configured' => [
 389                  'templatecontent' => 'No tags',
 390                  'expected' => '|^No tags$|',
 391                  'rolename' => 'editingteacher',
 392                  'enableexport' => false,
 393                  'approved' => true,
 394                  'enablecomments' => false,
 395                  'enableratings' => false,
 396                  'options' => ['ratings' => true],
 397              ],
 398              'Teacher adding ratings with ratings configured' => [
 399                  'templatecontent' => 'No tags',
 400                  'expected' => '|^No tags.*Average of ratings|',
 401                  'rolename' => 'editingteacher',
 402                  'enableexport' => false,
 403                  'approved' => true,
 404                  'enablecomments' => false,
 405                  'enableratings' => true,
 406                  'options' => ['ratings' => true],
 407              ],
 408              'Teacher actionsmenu tag with default options' => [
 409                  'templatecontent' => 'Some ##actionsmenu## tag',
 410                  'expected' => '|Some .*edit.*{entryid}.*sesskey.*Edit.* .*delete.*{entryid}.*sesskey.*Delete.* tag|',
 411                  'rolename' => 'editingteacher',
 412              ],
 413              'Teacher actionsmenu tag with default options (check Show more is not there)' => [
 414                  'templatecontent' => 'Some ##actionsmenu## tag',
 415                  'expected' => '|^Some((?!Show more).)*tag$|',
 416                  'rolename' => 'editingteacher',
 417              ],
 418              'Teacher actionsmenu tag with show more enabled' => [
 419                  'templatecontent' => 'Some ##actionsmenu## tag',
 420                  'expected' => '|Some .*view.*{cmid}.*rid.*{entryid}.*Show more.* .*Edit.* .*Delete.* tag|',
 421                  'rolename' => 'editingteacher',
 422                  'enableexport' => false,
 423                  'approved' => false,
 424                  'enablecomments' => false,
 425                  'enableratings' => false,
 426                  'options' => ['showmore' => true],
 427              ],
 428              'Teacher actionsmenu tag with export enabled' => [
 429                  'templatecontent' => 'Some ##actionsmenu## tag',
 430                  'expected' => '|Some .*Edit.* .*Delete.* .*portfolio/add.* tag|',
 431                  'rolename' => 'editingteacher',
 432                  'enableexport' => true,
 433              ],
 434              'Teacher actionsmenu tag with approved enabled' => [
 435                  'templatecontent' => 'Some ##actionsmenu## tag',
 436                  'expected' => '|Some .*Edit.* .*Delete.* .*disapprove.*{entryid}.*sesskey.*Undo approval.* tag|',
 437                  'rolename' => 'editingteacher',
 438                  'enableexport' => false,
 439                  'approved' => true,
 440              ],
 441              'Teacher actionsmenu tag with export, approved and showmore enabled' => [
 442                  'templatecontent' => 'Some ##actionsmenu## tag',
 443                  'expected' => '|Some .*Show more.* .*Edit.* .*Delete.* .*Undo approval.* .*Export to portfolio.* tag|',
 444                  'rolename' => 'editingteacher',
 445                  'enableexport' => true,
 446                  'approved' => true,
 447                  'enablecomments' => false,
 448                  'enableratings' => false,
 449                  'options' => ['showmore' => true],
 450              ],
 451              'Teacher otherfields tag' => [
 452                  'templatecontent' => 'Some ##otherfields## tag',
 453                  'expected' => '|Some .*{fieldname}.*Example entry.*otherfield.*Another example.* tag|',
 454                  'rolename' => 'editingteacher',
 455              ],
 456              'Teacher otherfields tag with some field in the template' => [
 457                  'templatecontent' => 'Some [[myfield]] and ##otherfields## tag',
 458                  'expected' => '|Some .*Example entry.* and .*otherfield.*Another example.* tag|',
 459                  'rolename' => 'editingteacher',
 460              ],
 461              // Student scenarios.
 462              'Student id tag' => [
 463                  'templatecontent' => 'Some ##id## tag',
 464                  'expected' => '|Some {entryid} tag|',
 465                  'rolename' => 'student',
 466              ],
 467              'Student delete tag' => [
 468                  'templatecontent' => 'Some ##delete## tag',
 469                  'expected' => '|Some .*delete.*{entryid}.*sesskey.*Delete.* tag|',
 470                  'rolename' => 'student',
 471              ],
 472              'Student delete tag on other author entry' => [
 473                  'templatecontent' => 'Some ##delete## tag',
 474                  'expected' => '|Some  tag|',
 475                  'rolename' => 'student',
 476                  'enableexport' => false,
 477                  'approved' => true,
 478                  'enablecomments' => false,
 479                  'enableratings' => false,
 480                  'options' => [],
 481                  'otherauthor' => true,
 482              ],
 483              'Student edit tag' => [
 484                  'templatecontent' => 'Some ##edit## tag',
 485                  'expected' => '|Some .*edit.*{entryid}.*sesskey.*Edit.* tag|',
 486                  'rolename' => 'student',
 487              ],
 488              'Student edit tag on other author entry' => [
 489                  'templatecontent' => 'Some ##edit## tag',
 490                  'expected' => '|Some  tag|',
 491                  'rolename' => 'student',
 492                  'enableexport' => false,
 493                  'approved' => true,
 494                  'enablecomments' => false,
 495                  'enableratings' => false,
 496                  'options' => [],
 497                  'otherauthor' => true,
 498              ],
 499              'Student more tag' => [
 500                  'templatecontent' => 'Some ##more## tag',
 501                  'expected' => '|Some .*more.*{cmid}.*rid.*{entryid}.*More.* tag|',
 502                  'rolename' => 'student',
 503                  'enableexport' => false,
 504                  'approved' => true,
 505                  'enablecomments' => false,
 506                  'enableratings' => false,
 507                  'options' => ['showmore' => true],
 508              ],
 509              'Student more tag with showmore set to false' => [
 510                  'templatecontent' => 'Some ##more## tag',
 511                  'expected' => '|Some  tag|',
 512                  'rolename' => 'student',
 513                  'enableexport' => false,
 514                  'approved' => true,
 515                  'enablecomments' => false,
 516                  'enableratings' => false,
 517                  'options' => ['showmore' => false],
 518              ],
 519              'Student moreurl tag' => [
 520                  'templatecontent' => 'Some ##moreurl## tag',
 521                  'expected' => '|Some .*/mod/data/view.*{cmid}.*rid.*{entryid}.* tag|',
 522                  'rolename' => 'student',
 523                  'enableexport' => false,
 524                  'approved' => true,
 525                  'enablecomments' => false,
 526                  'enableratings' => false,
 527                  'options' => ['showmore' => true],
 528              ],
 529              'Student moreurl tag with showmore set to false' => [
 530                  'templatecontent' => 'Some ##moreurl## tag',
 531                  'expected' => '|Some .*/mod/data/view.*{cmid}.*rid.*{entryid}.* tag|',
 532                  'rolename' => 'student',
 533                  'enableexport' => false,
 534                  'approved' => true,
 535                  'enablecomments' => false,
 536                  'enableratings' => false,
 537                  'options' => ['showmore' => false],
 538              ],
 539              'Student delcheck tag' => [
 540                  'templatecontent' => 'Some ##delcheck## tag',
 541                  'expected' => '|Some  tag|',
 542                  'rolename' => 'student',
 543              ],
 544              'Student user tag' => [
 545                  'templatecontent' => 'Some ##user## tag',
 546                  'expected' => '|Some .*user/view.*{authorid}.*course.*{courseid}.*{authorfullname}.* tag|',
 547                  'rolename' => 'student',
 548              ],
 549              'Student userpicture tag' => [
 550                  'templatecontent' => 'Some ##userpicture## tag',
 551                  'expected' => '|Some .*user/view.*{authorid}.*course.*{courseid}.* tag|',
 552                  'rolename' => 'student',
 553              ],
 554              'Student export tag' => [
 555                  'templatecontent' => 'Some ##export## tag',
 556                  'expected' => '|Some .*portfolio/add.* tag|',
 557                  'rolename' => 'student',
 558                  'enableexport' => true,
 559              ],
 560              'Student export tag not configured' => [
 561                  'templatecontent' => 'Some ##export## tag',
 562                  'expected' => '|Some  tag|',
 563                  'rolename' => 'student',
 564                  'enableexport' => false,
 565              ],
 566              'Student export tag on other user entry' => [
 567                  'templatecontent' => 'Some ##export## tag',
 568                  'expected' => '|Some  tag|',
 569                  'rolename' => 'student',
 570                  'enableexport' => false,
 571                  'approved' => true,
 572                  'enablecomments' => false,
 573                  'enableratings' => false,
 574                  'options' => [],
 575                  'otherauthor' => true,
 576              ],
 577              'Student timeadded tag' => [
 578                  'templatecontent' => 'Some ##timeadded## tag',
 579                  'expected' => '|Some <span.*>{timeadded}</span> tag|',
 580                  'rolename' => 'student',
 581              ],
 582              'Student timemodified tag' => [
 583                  'templatecontent' => 'Some ##timemodified## tag',
 584                  'expected' => '|Some <span.*>{timemodified}</span> tag|',
 585                  'rolename' => 'student',
 586              ],
 587              'Student approve tag approved entry' => [
 588                  'templatecontent' => 'Some ##approve## tag',
 589                  'expected' => '|Some  tag|',
 590                  'rolename' => 'student',
 591                  'enableexport' => false,
 592                  'approved' => true,
 593              ],
 594              'Student approve tag disapproved entry' => [
 595                  'templatecontent' => 'Some ##approve## tag',
 596                  'expected' => '|Some  tag|',
 597                  'rolename' => 'student',
 598                  'enableexport' => false,
 599                  'approved' => false,
 600              ],
 601              'Student disapprove tag approved entry' => [
 602                  'templatecontent' => 'Some ##disapprove## tag',
 603                  'expected' => '|Some  tag|',
 604                  'rolename' => 'student',
 605                  'enableexport' => false,
 606                  'approved' => true,
 607              ],
 608              'Student disapprove tag disapproved entry' => [
 609                  'templatecontent' => 'Some ##disapprove## tag',
 610                  'expected' => '|Some  tag|',
 611                  'rolename' => 'student',
 612                  'enableexport' => false,
 613                  'approved' => false,
 614              ],
 615              'Student approvalstatus tag approved entry' => [
 616                  'templatecontent' => 'Some ##approvalstatus## tag',
 617                  'expected' => '|Some  tag|',
 618                  'rolename' => 'student',
 619                  'enableexport' => false,
 620                  'approved' => true,
 621              ],
 622              'Student approvalstatus tag disapproved entry' => [
 623                  'templatecontent' => 'Some ##approvalstatus## tag',
 624                  'expected' => '|Some .*Pending approval.* tag|',
 625                  'rolename' => 'student',
 626                  'enableexport' => false,
 627                  'approved' => false,
 628              ],
 629              'Student approvalstatusclass tag approved entry' => [
 630                  'templatecontent' => 'Some ##approvalstatusclass## tag',
 631                  'expected' => '|Some approved tag|',
 632                  'rolename' => 'student',
 633                  'enableexport' => false,
 634                  'approved' => true,
 635              ],
 636              'Student approvalstatusclass tag disapproved entry' => [
 637                  'templatecontent' => 'Some ##approvalstatusclass## tag',
 638                  'expected' => '|Some notapproved tag|',
 639                  'rolename' => 'student',
 640                  'enableexport' => false,
 641                  'approved' => false,
 642              ],
 643              'Student tags tag' => [
 644                  'templatecontent' => 'Some ##tags## tag',
 645                  'expected' => '|Some .*Cats.* tag|',
 646                  'rolename' => 'student',
 647              ],
 648              'Student field name tag' => [
 649                  'templatecontent' => 'Some [[myfield]] tag',
 650                  'expected' => '|Some .*Example entry.* tag|',
 651                  'rolename' => 'student',
 652              ],
 653              'Student field#id name tag' => [
 654                  'templatecontent' => 'Some [[myfield#id]] tag',
 655                  'expected' => '|Some {fieldid} tag|',
 656                  'rolename' => 'student',
 657              ],
 658              'Student field#name tag' => [
 659                  'templatecontent' => 'Some [[myfield#name]] tag',
 660                  'expected' => '|Some {fieldname} tag|',
 661                  'rolename' => 'student',
 662              ],
 663              'Student field#description tag' => [
 664                  'templatecontent' => 'Some [[myfield#description]] tag',
 665                  'expected' => '|Some {fielddescription} tag|',
 666                  'rolename' => 'student',
 667              ],
 668              'Student comments name tag with comments enabled' => [
 669                  'templatecontent' => 'Some ##comments## tag',
 670                  'expected' => '|Some .*Comments.* tag|',
 671                  'rolename' => 'student',
 672                  'enableexport' => false,
 673                  'approved' => true,
 674                  'enablecomments' => true,
 675              ],
 676              'Student comments name tag with comments disabled' => [
 677                  'templatecontent' => 'Some ##comments## tag',
 678                  'expected' => '|Some  tag|',
 679                  'rolename' => 'student',
 680                  'enableexport' => false,
 681                  'approved' => true,
 682                  'enablecomments' => false,
 683              ],
 684              'Student comment forced with comments enables' => [
 685                  'templatecontent' => 'No tags',
 686                  'expected' => '|No tags.*Comments.*|',
 687                  'rolename' => 'student',
 688                  'enableexport' => false,
 689                  'approved' => true,
 690                  'enablecomments' => true,
 691                  'enableratings' => false,
 692                  'options' => ['comments' => true]
 693              ],
 694              'Student comment forced without comments enables' => [
 695                  'templatecontent' => 'No tags',
 696                  'expected' => '|^No tags$|',
 697                  'rolename' => 'student',
 698                  'enableexport' => false,
 699                  'approved' => true,
 700                  'enablecomments' => false,
 701                  'enableratings' => false,
 702                  'options' => ['comments' => true]
 703              ],
 704              'Student adding ratings without ratings configured' => [
 705                  'templatecontent' => 'No tags',
 706                  'expected' => '|^No tags$|',
 707                  'rolename' => 'student',
 708                  'enableexport' => false,
 709                  'approved' => true,
 710                  'enablecomments' => false,
 711                  'enableratings' => false,
 712                  'options' => ['ratings' => true]
 713              ],
 714              'Student adding ratings with ratings configured' => [
 715                  'templatecontent' => 'No tags',
 716                  'expected' => '|^No tags$|',
 717                  'rolename' => 'student',
 718                  'enableexport' => false,
 719                  'approved' => true,
 720                  'enablecomments' => false,
 721                  'enableratings' => true,
 722                  'options' => ['ratings' => true]
 723              ],
 724              'Student actionsmenu tag with default options' => [
 725                  'templatecontent' => 'Some ##actionsmenu## tag',
 726                  'expected' => '|Some .*edit.*{entryid}.*sesskey.*Edit.* .*delete.*{entryid}.*sesskey.*Delete.* tag|',
 727                  'rolename' => 'student',
 728              ],
 729              'Student actionsmenu tag with default options (check Show more is not there)' => [
 730                  'templatecontent' => 'Some ##actionsmenu## tag',
 731                  'expected' => '|^Some((?!Show more).)*tag$|',
 732                  'rolename' => 'student',
 733              ],
 734              'Student actionsmenu tag with show more enabled' => [
 735                  'templatecontent' => 'Some ##actionsmenu## tag',
 736                  'expected' => '|Some .*view.*{cmid}.*rid.*{entryid}.*Show more.* .*Edit.* .*Delete.* tag|',
 737                  'rolename' => 'student',
 738                  'enableexport' => false,
 739                  'approved' => false,
 740                  'enablecomments' => false,
 741                  'enableratings' => false,
 742                  'options' => ['showmore' => true],
 743              ],
 744              'Student actionsmenu tag with export enabled' => [
 745                  'templatecontent' => 'Some ##actionsmenu## tag',
 746                  'expected' => '|Some .*Edit.* .*Delete.* .*portfolio/add.* tag|',
 747                  'rolename' => 'student',
 748                  'enableexport' => true,
 749              ],
 750              'Student actionsmenu tag with approved enabled' => [
 751                  'templatecontent' => 'Some ##actionsmenu## tag',
 752                  'expected' => '|^Some((?!Approve).)*tag$|',
 753                  'rolename' => 'student',
 754                  'enableexport' => false,
 755                  'approved' => true,
 756              ],
 757              'Student actionsmenu tag with export, approved and showmore enabled' => [
 758                  'templatecontent' => 'Some ##actionsmenu## tag',
 759                  'expected' => '|Some .*Show more.* .*Edit.* .*Delete.* .*Export to portfolio.* tag|',
 760                  'rolename' => 'student',
 761                  'enableexport' => true,
 762                  'approved' => true,
 763                  'enablecomments' => false,
 764                  'enableratings' => false,
 765                  'options' => ['showmore' => true],
 766              ],
 767              'Student otherfields tag' => [
 768                  'templatecontent' => 'Some ##otherfields## tag',
 769                  'expected' => '|Some .*{fieldname}.*Example entry.*otherfield.*Another example.* tag|',
 770                  'rolename' => 'student',
 771              ],
 772              'Student otherfields tag with some field in the template' => [
 773                  'templatecontent' => 'Some [[myfield]] and ##otherfields## tag',
 774                  'expected' => '|Some .*Example entry.* and .*otherfield.*Another example.* tag|',
 775                  'rolename' => 'student',
 776              ],
 777          ];
 778      }
 779  
 780      /**
 781       * Create all the necessary data to enable portfolio export in mod_data
 782       *
 783       * @param stdClass $user the current user record.
 784       */
 785      protected function enable_portfolio(stdClass $user) {
 786          global $DB;
 787          set_config('enableportfolios', 1);
 788  
 789          $plugin = 'download';
 790          $name = 'Download';
 791  
 792          $portfolioinstance = (object) [
 793              'plugin' => $plugin,
 794              'name' => $name,
 795              'visible' => 1
 796          ];
 797          $portfolioinstance->id = $DB->insert_record('portfolio_instance', $portfolioinstance);
 798          $userinstance = (object) [
 799              'instance' => $portfolioinstance->id,
 800              'userid' => $user->id,
 801              'name' => 'visible',
 802              'value' => 1
 803          ];
 804          $DB->insert_record('portfolio_instance_user', $userinstance);
 805  
 806          $DB->insert_record('portfolio_log', [
 807              'portfolio' => $portfolioinstance->id,
 808              'userid' => $user->id,
 809              'caller_class' => 'data_portfolio_caller',
 810              'caller_component' => 'mod_data',
 811              'time' => time(),
 812          ]);
 813      }
 814  
 815      /**
 816       * Enable the ratings on the database entries.
 817       *
 818       * @param context_module $context the activity context
 819       * @param stdClass $activity the activity record
 820       * @param array $entries database entries
 821       * @param stdClass $user the current user record
 822       * @return stdClass the entries with the rating attribute
 823       */
 824      protected function enable_ratings(context_module $context, stdClass $activity, array $entries, stdClass $user) {
 825          global $CFG;
 826          $ratingoptions = (object)[
 827              'context' => $context,
 828              'component' => 'mod_data',
 829              'ratingarea' => 'entry',
 830              'items' => $entries,
 831              'aggregate' => RATING_AGGREGATE_AVERAGE,
 832              'scaleid' => $activity->scale,
 833              'userid' => $user->id,
 834              'returnurl' => $CFG->wwwroot . '/mod/data/view.php',
 835              'assesstimestart' => $activity->assesstimestart,
 836              'assesstimefinish' => $activity->assesstimefinish,
 837          ];
 838          $rm = new rating_manager();
 839          return $rm->get_ratings($ratingoptions);
 840      }
 841  
 842      /**
 843       * Test parse add entry template parsing.
 844       *
 845       * @covers ::parse_add_entry
 846       * @dataProvider parse_add_entry_provider
 847       * @param string $templatecontent the template string
 848       * @param string $expected expected output
 849       * @param bool $newentry if it is a new entry or editing and existing one
 850       */
 851      public function test_parse_add_entry(
 852          string $templatecontent,
 853          string $expected,
 854          bool $newentry = false
 855      ) {
 856          global $DB, $PAGE;
 857          // Comments, tags, approval, user role.
 858          $this->resetAfterTest();
 859  
 860          $params = ['approval' => true];
 861  
 862          $course = $this->getDataGenerator()->create_course();
 863          $params['course'] = $course;
 864          $activity = $this->getDataGenerator()->create_module('data', $params);
 865          $author = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
 866  
 867          // Generate an entry.
 868          $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 869          $fieldrecord = (object)[
 870              'name' => 'myfield',
 871              'type' => 'text',
 872              'description' => 'This is a field'
 873          ];
 874          $field = $generator->create_field($fieldrecord, $activity);
 875          $otherfieldrecord = (object)['name' => 'otherfield', 'type' => 'text'];
 876          $otherfield = $generator->create_field($otherfieldrecord, $activity);
 877  
 878          if ($newentry) {
 879              $entryid = null;
 880              $entry = null;
 881          } else {
 882              $entryid = $generator->create_entry(
 883                  $activity,
 884                  [
 885                      $field->field->id => 'Example entry',
 886                      $otherfield->field->id => 'Another example',
 887                  ],
 888                  0,
 889                  ['Cats', 'Dogs']
 890              );
 891              $entry = (object)[
 892                  'd' => $activity->id,
 893                  'rid' => $entryid,
 894                  "field_{$field->field->id}" => "New value",
 895                  "field_{$otherfield->field->id}" => "Altered value",
 896              ];
 897          }
 898  
 899          $manager = manager::create_from_instance($activity);
 900  
 901          // Some cooked variables for the regular expression.
 902          $replace = [
 903              '{fieldid}' => $field->field->id,
 904              '{fieldname}' => $field->field->name,
 905              '{fielddescription}' => $field->field->description,
 906              '{otherid}' => $otherfield->field->id,
 907          ];
 908  
 909          $processdata = (object)[
 910              'generalnotifications' => ['GENERAL'],
 911              'fieldnotifications' => [
 912                  $field->field->name => ['FIELD'],
 913                  $otherfield->field->name => ['OTHERFIELD'],
 914              ],
 915          ];
 916  
 917          $parser = new template($manager, $templatecontent);
 918          $result = $parser->parse_add_entry($processdata, $entryid, $entry);
 919  
 920          // We don't want line breaks for the validations.
 921          $result = str_replace("\n", '', $result);
 922          $regexp = str_replace(array_keys($replace), array_values($replace), $expected);
 923          $this->assertMatchesRegularExpression($regexp, $result);
 924      }
 925  
 926      /**
 927       * Data provider for test_parse_add_entry().
 928       *
 929       * @return array of scenarios
 930       */
 931      public function parse_add_entry_provider(): array {
 932          return [
 933              // Editing an entry.
 934              'Teacher editing entry tags tag' => [
 935                  'templatecontent' => 'Some ##tags## tag',
 936                  'expected' => '|GENERAL.*Some .*select .*tags.*Cats.* tag|',
 937                  'newentry' => false,
 938              ],
 939              'Teacher editing entry field name tag' => [
 940                  'templatecontent' => 'Some [[myfield]] tag',
 941                  'expected' => '|GENERAL.*Some .*FIELD.*field_{fieldid}.*input.*New value.* tag|',
 942                  'newentry' => false,
 943              ],
 944              'Teacher editing entry field#id tag' => [
 945                  'templatecontent' => 'Some [[myfield#id]] tag',
 946                  'expected' => '|GENERAL.*Some field_{fieldid} tag|',
 947                  'newentry' => false,
 948              ],
 949              'Teacher editing field#name tag' => [
 950                  'templatecontent' => 'Some [[myfield#name]] tag',
 951                  'expected' => '|GENERAL.*Some {fieldname} tag|',
 952                  'newentry' => false,
 953              ],
 954              'Teacher editing field#description tag' => [
 955                  'templatecontent' => 'Some [[myfield#description]] tag',
 956                  'expected' => '|GENERAL.*Some {fielddescription} tag|',
 957                  'newentry' => false,
 958              ],
 959              'Teacher editing entry field otherfields tag' => [
 960                  'templatecontent' => 'Some [[myfield]] and ##otherfields## tag',
 961                  'expected' => '|GENERAL.*Some .*FIELD.*field_{fieldid}.*input.*New value.* '
 962                                . 'and .*OTHERFIELD.*field_{otherid}.*input.*Altered value.* tag|',
 963                  'newentry' => false,
 964              ],
 965              // New entry.
 966              'Teacher new entry tags tag' => [
 967                  'templatecontent' => 'Some ##tags## tag',
 968                  'expected' => '|GENERAL.*Some .*select .*tags\[\].* tag|',
 969                  'newentry' => true,
 970              ],
 971              'Teacher new entry field name tag' => [
 972                  'templatecontent' => 'Some [[myfield]] tag',
 973                  'expected' => '|GENERAL.*Some .*FIELD.*field_{fieldid}.*input.*value="".* tag|',
 974                  'newentry' => true,
 975              ],
 976              'Teacher new entry field#id name tag' => [
 977                  'templatecontent' => 'Some [[myfield#id]] tag',
 978                  'expected' => '|GENERAL.*Some field_{fieldid} tag|',
 979                  'newentry' => true,
 980              ],
 981              'Teacher new entry field#name tag' => [
 982                  'templatecontent' => 'Some [[myfield#name]] tag',
 983                  'expected' => '|GENERAL.*Some {fieldname} tag|',
 984                  'newentry' => false,
 985              ],
 986              'Teacher new entry field#description tag' => [
 987                  'templatecontent' => 'Some [[myfield#description]] tag',
 988                  'expected' => '|GENERAL.*Some {fielddescription} tag|',
 989                  'newentry' => false,
 990              ],
 991              'Teacher new entry field otherfields tag' => [
 992                  'templatecontent' => 'Some [[myfield]] and ##otherfields## tag',
 993                  'expected' => '|GENERAL.*Some .*FIELD.*field_{fieldid}.*input.*New value.* '
 994                                . '.* and .*OTHERFIELD.*field_{otherid}.*input.*Altered value.* |',
 995                  'newentry' => false,
 996              ],
 997          ];
 998      }
 999  }