Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 39 and 401]

   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   * Unit tests for mod_folder lib
  19   *
  20   * @package    mod_folder
  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 3.0
  25   */
  26  namespace mod_folder;
  27  
  28  use context_user;
  29  use context_module;
  30  
  31  defined('MOODLE_INTERNAL') || die();
  32  
  33  
  34  /**
  35   * Unit tests for mod_folder lib
  36   *
  37   * @package    mod_folder
  38   * @category   external
  39   * @copyright  2015 Juan Leyva <juan@moodle.com>
  40   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  41   * @since      Moodle 3.0
  42   */
  43  class lib_test extends \advanced_testcase {
  44  
  45      /**
  46       * Setup.
  47       */
  48      public function setUp(): void {
  49          $this->resetAfterTest();
  50          $this->setAdminUser();
  51      }
  52  
  53      /**
  54       * Prepares things before this test case is initialised
  55       * @return void
  56       */
  57      public static function setUpBeforeClass(): void {
  58          global $CFG;
  59          require_once($CFG->dirroot . '/mod/folder/lib.php');
  60      }
  61  
  62      /**
  63       * Test folder_view
  64       * @return void
  65       */
  66      public function test_folder_view() {
  67          global $CFG;
  68  
  69          $CFG->enablecompletion = 1;
  70  
  71          // Setup test data.
  72          $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
  73          $folder = $this->getDataGenerator()->create_module('folder', array('course' => $course->id),
  74                                                              array('completion' => 2, 'completionview' => 1));
  75          $context = \context_module::instance($folder->cmid);
  76          $cm = get_coursemodule_from_instance('folder', $folder->id);
  77  
  78          // Trigger and capture the event.
  79          $sink = $this->redirectEvents();
  80  
  81          folder_view($folder, $course, $cm, $context);
  82  
  83          $events = $sink->get_events();
  84          // 2 additional events thanks to completion.
  85          $this->assertCount(3, $events);
  86          $event = array_shift($events);
  87  
  88          // Checking that the event contains the expected values.
  89          $this->assertInstanceOf('\mod_folder\event\course_module_viewed', $event);
  90          $this->assertEquals($context, $event->get_context());
  91          $moodleurl = new \moodle_url('/mod/folder/view.php', array('id' => $cm->id));
  92          $this->assertEquals($moodleurl, $event->get_url());
  93          $this->assertEventContextNotUsed($event);
  94          $this->assertNotEmpty($event->get_name());
  95  
  96          // Check completion status.
  97          $completion = new \completion_info($course);
  98          $completiondata = $completion->get_data($cm);
  99          $this->assertEquals(1, $completiondata->completionstate);
 100      }
 101  
 102      public function test_folder_core_calendar_provide_event_action() {
 103          // Create the activity.
 104          $course = $this->getDataGenerator()->create_course();
 105          $folder = $this->getDataGenerator()->create_module('folder', array('course' => $course->id));
 106  
 107          // Create a calendar event.
 108          $event = $this->create_action_event($course->id, $folder->id,
 109              \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
 110  
 111          // Create an action factory.
 112          $factory = new \core_calendar\action_factory();
 113  
 114          // Decorate action event.
 115          $actionevent = mod_folder_core_calendar_provide_event_action($event, $factory);
 116  
 117          // Confirm the event was decorated.
 118          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
 119          $this->assertEquals(get_string('view'), $actionevent->get_name());
 120          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
 121          $this->assertEquals(1, $actionevent->get_item_count());
 122          $this->assertTrue($actionevent->is_actionable());
 123      }
 124  
 125      public function test_folder_core_calendar_provide_event_action_for_non_user() {
 126          global $CFG;
 127  
 128          // Create a course.
 129          $course = $this->getDataGenerator()->create_course();
 130  
 131          // Create the activity.
 132          $folder = $this->getDataGenerator()->create_module('folder', array('course' => $course->id));
 133  
 134          // Create a calendar event.
 135          $event = $this->create_action_event($course->id, $folder->id,
 136                  \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
 137  
 138          // Now, log out.
 139          $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities.
 140          $this->setUser();
 141  
 142          // Create an action factory.
 143          $factory = new \core_calendar\action_factory();
 144  
 145          // Decorate action event.
 146          $actionevent = mod_folder_core_calendar_provide_event_action($event, $factory);
 147  
 148          // Confirm the event is not shown at all.
 149          $this->assertNull($actionevent);
 150      }
 151  
 152      public function test_folder_core_calendar_provide_event_action_in_hidden_section() {
 153          // Create a course.
 154          $course = $this->getDataGenerator()->create_course();
 155  
 156          // Create a student.
 157          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 158  
 159          // Create the activity.
 160          $folder = $this->getDataGenerator()->create_module('folder', array('course' => $course->id));
 161  
 162          // Create a calendar event.
 163          $event = $this->create_action_event($course->id, $folder->id,
 164                  \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
 165  
 166          // Set sections 0 as hidden.
 167          set_section_visible($course->id, 0, 0);
 168  
 169          // Create an action factory.
 170          $factory = new \core_calendar\action_factory();
 171  
 172          // Decorate action event.
 173          $actionevent = mod_folder_core_calendar_provide_event_action($event, $factory, $student->id);
 174  
 175          // Confirm the event is not shown at all.
 176          $this->assertNull($actionevent);
 177      }
 178  
 179      public function test_folder_core_calendar_provide_event_action_for_user() {
 180          // Create a course.
 181          $course = $this->getDataGenerator()->create_course();
 182  
 183          // Create a student.
 184          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 185  
 186          // Create the activity.
 187          $folder = $this->getDataGenerator()->create_module('folder', array('course' => $course->id));
 188  
 189          // Create a calendar event.
 190          $event = $this->create_action_event($course->id, $folder->id,
 191                  \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
 192  
 193          // Now, log out.
 194          $this->setUser();
 195  
 196          // Create an action factory.
 197          $factory = new \core_calendar\action_factory();
 198  
 199          // Decorate action event for the student.
 200          $actionevent = mod_folder_core_calendar_provide_event_action($event, $factory, $student->id);
 201  
 202          // Confirm the event was decorated.
 203          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
 204          $this->assertEquals(get_string('view'), $actionevent->get_name());
 205          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
 206          $this->assertEquals(1, $actionevent->get_item_count());
 207          $this->assertTrue($actionevent->is_actionable());
 208      }
 209  
 210      public function test_folder_core_calendar_provide_event_action_already_completed() {
 211          global $CFG;
 212  
 213          $CFG->enablecompletion = 1;
 214  
 215          // Create the activity.
 216          $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
 217          $folder = $this->getDataGenerator()->create_module('folder', array('course' => $course->id),
 218              array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
 219  
 220          // Get some additional data.
 221          $cm = get_coursemodule_from_instance('folder', $folder->id);
 222  
 223          // Create a calendar event.
 224          $event = $this->create_action_event($course->id, $folder->id,
 225              \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
 226  
 227          // Mark the activity as completed.
 228          $completion = new \completion_info($course);
 229          $completion->set_module_viewed($cm);
 230  
 231          // Create an action factory.
 232          $factory = new \core_calendar\action_factory();
 233  
 234          // Decorate action event.
 235          $actionevent = mod_folder_core_calendar_provide_event_action($event, $factory);
 236  
 237          // Ensure result was null.
 238          $this->assertNull($actionevent);
 239      }
 240  
 241      public function test_folder_core_calendar_provide_event_action_already_completed_for_user() {
 242          global $CFG;
 243  
 244          $CFG->enablecompletion = 1;
 245  
 246          // Create a course.
 247          $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
 248  
 249          // Create a student.
 250          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 251  
 252          // Create the activity.
 253          $folder = $this->getDataGenerator()->create_module('folder', array('course' => $course->id),
 254                  array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
 255  
 256          // Get some additional data.
 257          $cm = get_coursemodule_from_instance('folder', $folder->id);
 258  
 259          // Create a calendar event.
 260          $event = $this->create_action_event($course->id, $folder->id,
 261                  \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
 262  
 263          // Mark the activity as completed for the student.
 264          $completion = new \completion_info($course);
 265          $completion->set_module_viewed($cm, $student->id);
 266  
 267          // Now, log out.
 268          $this->setUser();
 269  
 270          // Create an action factory.
 271          $factory = new \core_calendar\action_factory();
 272  
 273          // Decorate action event for the student.
 274          $actionevent = mod_folder_core_calendar_provide_event_action($event, $factory, $student->id);
 275  
 276          // Ensure result was null.
 277          $this->assertNull($actionevent);
 278      }
 279  
 280      /**
 281       * Creates an action event.
 282       *
 283       * @param int $courseid The course id.
 284       * @param int $instanceid The instance id.
 285       * @param string $eventtype The event type.
 286       * @return bool|calendar_event
 287       */
 288      private function create_action_event($courseid, $instanceid, $eventtype) {
 289          $event = new \stdClass();
 290          $event->name = 'Calendar event';
 291          $event->modulename  = 'folder';
 292          $event->courseid = $courseid;
 293          $event->instance = $instanceid;
 294          $event->type = CALENDAR_EVENT_TYPE_ACTION;
 295          $event->eventtype = $eventtype;
 296          $event->timestart = time();
 297  
 298          return \calendar_event::create($event);
 299      }
 300  
 301      /**
 302       * Test Get recent mod activity method.
 303       * @covers ::folder_get_recent_mod_activity
 304       * @dataProvider folder_get_recent_mod_activity_provider
 305       *
 306       * @param int $forcedownload The forcedownload option.
 307       * @param bool $hascapability if the user has the mod/folder:view capability
 308       * @param int $count The expected recent activities entries.
 309       */
 310      public function test_folder_get_recent_mod_activity(int $forcedownload, bool $hascapability, int $count) {
 311          global $USER, $DB;
 312  
 313          $this->resetAfterTest();
 314          $this->setAdminUser();
 315  
 316          $course = $this->getDataGenerator()->create_course();
 317  
 318          // Add files to draft area.
 319          $filesitem = file_get_unused_draft_itemid();
 320          $usercontext = context_user::instance($USER->id);
 321          $filerecord = [
 322              'component' => 'user',
 323              'filearea' => 'draft',
 324              'contextid' => $usercontext->id,
 325              'itemid' => $filesitem,
 326              'filename' => 'file1.txt', 'filepath' => '/',
 327          ];
 328          $fs = get_file_storage();
 329          $fs->create_file_from_string($filerecord, 'First test file contents');
 330          // And a second file.
 331          $filerecord['filename'] = 'file2.txt';
 332          $fs->create_file_from_string($filerecord, 'Second test file contents');
 333  
 334          // Create the activity.
 335          $module = $this->getDataGenerator()->create_module(
 336              'folder',
 337              ['course' => $course->id, 'forcedownload' => $forcedownload, 'files' => $filesitem]
 338          );
 339  
 340          // Get some additional data.
 341          $cm = get_coursemodule_from_instance('folder', $module->id);
 342          $context = context_module::instance($cm->id);
 343  
 344          // Add user with the specific capability.
 345          $user = $this->getDataGenerator()->create_user();
 346          $this->getDataGenerator()->enrol_user($user->id, $course->id, 'editingteacher');
 347          if (!$hascapability) {
 348              // The recent activiy uses "folder:view" capability which is allowed by default.
 349              $role = $DB->get_record('role', ['shortname' => 'editingteacher'], '*', MUST_EXIST);
 350              assign_capability('mod/folder:view', CAP_PROHIBIT, $role->id, $context->id, true);
 351          }
 352          $this->setUser($user);
 353  
 354          // Get the recent activity.
 355          $index = 1;
 356          $activities = [];
 357          folder_get_recent_mod_activity($activities, $index, time() - HOURSECS, $course->id, $cm->id);
 358  
 359          // Check recent activity.
 360          $this->assertCount($count, $activities);
 361          foreach ($activities as $index => $activity) {
 362              $this->assertEquals('folder', $activity->type);
 363              $content = $activity->content;
 364              $this->assertEquals("file{$index}.txt", $content->filename);
 365              $urlparams = $content->url->params();
 366              if ($forcedownload) {
 367                  $this->assertEquals(1, $urlparams['forcedownload']);
 368              } else {
 369                  $this->assertArrayNotHasKey('forcedownload', $urlparams);
 370              }
 371          }
 372      }
 373  
 374      /**
 375       * Data provider for test_folder_get_recent_mod_activity().
 376       *
 377       * @return array
 378       */
 379      public function folder_get_recent_mod_activity_provider(): array {
 380          return [
 381              'Teacher with force download' => [
 382                  'forcedownload' => 1,
 383                  'hascapability' => true,
 384                  'count' => 2,
 385              ],
 386              'Teacher with no force download' => [
 387                  'forcedownload' => 0,
 388                  'hascapability' => true,
 389                  'count' => 2,
 390              ],
 391              'Invalid user with force download' => [
 392                  'forcedownload' => 1,
 393                  'hascapability' => false,
 394                  'count' => 0,
 395              ],
 396              'Invalid user with no force download' => [
 397                  'forcedownload' => 0,
 398                  'hascapability' => false,
 399                  'count' => 0,
 400              ],
 401          ];
 402      }
 403  }