Search moodle.org's
Developer Documentation

  • Bug fixes for general core bugs in 3.7.x will end 11 May 2020 (12 months).
  • Bug fixes for security issues in 3.7.x will end 9 November 2020 (18 months) - Support has ended.
  • minimum PHP 7.1.0 Note: minimum PHP version has increased since Moodle 3.6. PHP 7.2.x and 7.3.x are supported too. PHP 7.x could have some engine limitations.
  • Differences Between: [Versions 37 and 311] [Versions 37 and 400]

       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   * Unit tests for (some of) mod/feedback/lib.php.
      18   *
      19   * @package    mod_feedback
      20   * @copyright  2016 Stephen Bourget
      21   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      22   */
      23  defined('MOODLE_INTERNAL') || die();
      24  global $CFG;
      25  require_once($CFG->dirroot . '/mod/feedback/lib.php');
      26  
      27  /**
      28   * Unit tests for (some of) mod/feedback/lib.php.
      29   *
      30   * @copyright  2016 Stephen Bourget
      31   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      32   */
      33  class mod_feedback_lib_testcase extends advanced_testcase {
      34  
      35      public function test_feedback_initialise() {
      36          $this->resetAfterTest();
      37          $this->setAdminUser();
      38  
      39          $course = $this->getDataGenerator()->create_course();
      40          $params['course'] = $course->id;
      41          $params['timeopen'] = time() - 5 * MINSECS;
      42          $params['timeclose'] = time() + DAYSECS;
      43          $params['anonymous'] = 1;
      44          $params['intro'] = 'Some introduction text';
      45          $feedback = $this->getDataGenerator()->create_module('feedback', $params);
      46  
      47          // Test different ways to construct the structure object.
      48          $pseudocm = get_coursemodule_from_instance('feedback', $feedback->id); // Object similar to cm_info.
      49          $cm = get_fast_modinfo($course)->instances['feedback'][$feedback->id]; // Instance of cm_info.
      50  
      51          $constructorparams = [
      52              [$feedback, null],
      53              [null, $pseudocm],
      54              [null, $cm],
      55              [$feedback, $pseudocm],
      56              [$feedback, $cm],
      57          ];
      58  
      59          foreach ($constructorparams as $params) {
      60              $structure = new mod_feedback_completion($params[0], $params[1], 0);
      61              $this->assertTrue($structure->is_open());
      62              $this->assertTrue($structure->get_cm() instanceof cm_info);
      63              $this->assertEquals($feedback->cmid, $structure->get_cm()->id);
      64              $this->assertEquals($feedback->intro, $structure->get_feedback()->intro);
      65          }
      66      }
      67  
      68      /**
      69       * Tests for mod_feedback_refresh_events.
      70       */
      71      public function test_feedback_refresh_events() {
      72          global $DB;
      73          $this->resetAfterTest();
      74          $this->setAdminUser();
      75  
      76          $timeopen = time();
      77          $timeclose = time() + 86400;
      78  
      79          $course = $this->getDataGenerator()->create_course();
      80          $generator = $this->getDataGenerator()->get_plugin_generator('mod_feedback');
      81          $params['course'] = $course->id;
      82          $params['timeopen'] = $timeopen;
      83          $params['timeclose'] = $timeclose;
      84          $feedback = $generator->create_instance($params);
      85          $cm = get_coursemodule_from_instance('feedback', $feedback->id);
      86          $context = context_module::instance($cm->id);
      87  
      88          // Normal case, with existing course.
      89          $this->assertTrue(feedback_refresh_events($course->id));
      90          $eventparams = array('modulename' => 'feedback', 'instance' => $feedback->id, 'eventtype' => 'open');
      91          $openevent = $DB->get_record('event', $eventparams, '*', MUST_EXIST);
      92          $this->assertEquals($openevent->timestart, $timeopen);
      93  
      94          $eventparams = array('modulename' => 'feedback', 'instance' => $feedback->id, 'eventtype' => 'close');
      95          $closeevent = $DB->get_record('event', $eventparams, '*', MUST_EXIST);
      96          $this->assertEquals($closeevent->timestart, $timeclose);
      97          // In case the course ID is passed as a numeric string.
      98          $this->assertTrue(feedback_refresh_events('' . $course->id));
      99          // Course ID not provided.
     100          $this->assertTrue(feedback_refresh_events());
     101          $eventparams = array('modulename' => 'feedback');
     102          $events = $DB->get_records('event', $eventparams);
     103          foreach ($events as $event) {
     104              if ($event->modulename === 'feedback' && $event->instance === $feedback->id && $event->eventtype === 'open') {
     105                  $this->assertEquals($event->timestart, $timeopen);
     106              }
     107              if ($event->modulename === 'feedback' && $event->instance === $feedback->id && $event->eventtype === 'close') {
     108                  $this->assertEquals($event->timestart, $timeclose);
     109              }
     110          }
     111      }
     112  
     113      /**
     114       * Test check_updates_since callback.
     115       */
     116      public function test_check_updates_since() {
     117          global $DB;
     118  
     119          $this->resetAfterTest();
     120          $this->setAdminUser();
     121          $course = $this->getDataGenerator()->create_course();
     122  
     123          // Create user.
     124          $student = self::getDataGenerator()->create_user();
     125  
     126          // User enrolment.
     127          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
     128          $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual');
     129  
     130          $this->setCurrentTimeStart();
     131          $record = array(
     132              'course' => $course->id,
     133              'custom' => 0,
     134              'feedback' => 1,
     135          );
     136          $feedback = $this->getDataGenerator()->create_module('feedback', $record);
     137          $cm = get_coursemodule_from_instance('feedback', $feedback->id, $course->id);
     138          $cm = cm_info::create($cm);
     139  
     140          $this->setUser($student);
     141          // Check that upon creation, the updates are only about the new configuration created.
     142          $onehourago = time() - HOURSECS;
     143          $updates = feedback_check_updates_since($cm, $onehourago);
     144          foreach ($updates as $el => $val) {
     145              if ($el == 'configuration') {
     146                  $this->assertTrue($val->updated);
     147                  $this->assertTimeCurrent($val->timeupdated);
     148              } else {
     149                  $this->assertFalse($val->updated);
     150              }
     151          }
     152  
     153          $record = [
     154              'feedback' => $feedback->id,
     155              'userid' => $student->id,
     156              'timemodified' => time(),
     157              'random_response' => 0,
     158              'anonymous_response' => FEEDBACK_ANONYMOUS_NO,
     159              'courseid' => $course->id,
     160          ];
     161          $DB->insert_record('feedback_completed', (object)$record);
     162          $DB->insert_record('feedback_completedtmp', (object)$record);
     163  
     164          // Check now for finished and unfinished attempts.
     165          $updates = feedback_check_updates_since($cm, $onehourago);
     166          $this->assertTrue($updates->attemptsunfinished->updated);
     167          $this->assertCount(1, $updates->attemptsunfinished->itemids);
     168  
     169          $this->assertTrue($updates->attemptsfinished->updated);
     170          $this->assertCount(1, $updates->attemptsfinished->itemids);
     171      }
     172  
     173      /**
     174       * Test calendar event provide action open.
     175       */
     176      public function test_feedback_core_calendar_provide_event_action_open() {
     177          $this->resetAfterTest();
     178          $this->setAdminUser();
     179  
     180          $now = time();
     181          $course = $this->getDataGenerator()->create_course();
     182          $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id,
     183                  'timeopen' => $now - DAYSECS, 'timeclose' => $now + DAYSECS]);
     184          $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
     185  
     186          $factory = new \core_calendar\action_factory();
     187          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory);
     188  
     189          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
     190          $this->assertEquals(get_string('answerquestions', 'feedback'), $actionevent->get_name());
     191          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
     192          $this->assertEquals(1, $actionevent->get_item_count());
     193          $this->assertTrue($actionevent->is_actionable());
     194      }
     195  
     196      /**
     197       * Test calendar event provide action open, viewed by a different user.
     198       */
     199      public function test_feedback_core_calendar_provide_event_action_open_for_user() {
     200          global $DB;
     201  
     202          $this->resetAfterTest();
     203          $this->setAdminUser();
     204  
     205          $now = time();
     206          $user = $this->getDataGenerator()->create_user();
     207          $user2 = $this->getDataGenerator()->create_user();
     208          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
     209          $course = $this->getDataGenerator()->create_course();
     210          $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id, 'manual');
     211  
     212          $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id,
     213              'timeopen' => $now - DAYSECS, 'timeclose' => $now + DAYSECS]);
     214          $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
     215          $factory = new \core_calendar\action_factory();
     216  
     217          $this->setUser($user2);
     218  
     219          // User2 checking their events.
     220          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user2->id);
     221          $this->assertNull($actionevent);
     222  
     223          // User2 checking $user's events.
     224          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user->id);
     225          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
     226          $this->assertEquals(get_string('answerquestions', 'feedback'), $actionevent->get_name());
     227          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
     228          $this->assertEquals(1, $actionevent->get_item_count());
     229          $this->assertTrue($actionevent->is_actionable());
     230      }
     231  
     232      /**
     233       * Test calendar event provide action closed.
     234       */
     235      public function test_feedback_core_calendar_provide_event_action_closed() {
     236          $this->resetAfterTest();
     237          $this->setAdminUser();
     238  
     239          $course = $this->getDataGenerator()->create_course();
     240          $feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course->id,
     241                  'timeclose' => time() - DAYSECS));
     242          $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
     243  
     244          $factory = new \core_calendar\action_factory();
     245          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory);
     246  
     247          // No event on the dashboard if feedback is closed.
     248          $this->assertNull($actionevent);
     249      }
     250  
     251      /**
     252       * Test calendar event provide action closed, viewed by a different user.
     253       */
     254      public function test_feedback_core_calendar_provide_event_action_closed_for_user() {
     255          global $DB;
     256  
     257          $this->resetAfterTest();
     258          $this->setAdminUser();
     259  
     260          $course = $this->getDataGenerator()->create_course();
     261          $user = $this->getDataGenerator()->create_user();
     262          $user2 = $this->getDataGenerator()->create_user();
     263          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
     264          $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id, 'manual');
     265  
     266          $feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course->id,
     267              'timeclose' => time() - DAYSECS));
     268          $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
     269          $factory = new \core_calendar\action_factory();
     270          $this->setUser($user2);
     271  
     272          // User2 checking their events.
     273          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user2->id);
     274          $this->assertNull($actionevent);
     275  
     276          // User2 checking $user's events.
     277          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user->id);
     278  
     279          // No event on the dashboard if feedback is closed.
     280          $this->assertNull($actionevent);
     281      }
     282  
     283      /**
     284       * Test calendar event action open in future.
     285       *
     286       * @throws coding_exception
     287       */
     288      public function test_feedback_core_calendar_provide_event_action_open_in_future() {
     289          $this->resetAfterTest();
     290          $this->setAdminUser();
     291  
     292          $course = $this->getDataGenerator()->create_course();
     293          $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id,
     294                  'timeopen' => time() + DAYSECS]);
     295          $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
     296  
     297          $factory = new \core_calendar\action_factory();
     298          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory);
     299  
     300          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
     301          $this->assertEquals(get_string('answerquestions', 'feedback'), $actionevent->get_name());
     302          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
     303          $this->assertEquals(1, $actionevent->get_item_count());
     304          $this->assertFalse($actionevent->is_actionable());
     305      }
     306  
     307      /**
     308       * Test calendar event action open in future, viewed by a different user.
     309       *
     310       * @throws coding_exception
     311       */
     312      public function test_feedback_core_calendar_provide_event_action_open_in_future_for_user() {
     313          global $DB;
     314  
     315          $this->resetAfterTest();
     316          $this->setAdminUser();
     317  
     318          $course = $this->getDataGenerator()->create_course();
     319          $user = $this->getDataGenerator()->create_user();
     320          $user2 = $this->getDataGenerator()->create_user();
     321          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
     322          $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id, 'manual');
     323  
     324          $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id,
     325              'timeopen' => time() + DAYSECS]);
     326          $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
     327  
     328          $factory = new \core_calendar\action_factory();
     329          $this->setUser($user2);
     330  
     331          // User2 checking their events.
     332          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user2->id);
     333          $this->assertNull($actionevent);
     334  
     335          // User2 checking $user's events.
     336          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user->id);
     337  
     338          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
     339          $this->assertEquals(get_string('answerquestions', 'feedback'), $actionevent->get_name());
     340          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
     341          $this->assertEquals(1, $actionevent->get_item_count());
     342          $this->assertFalse($actionevent->is_actionable());
     343      }
     344  
     345      /**
     346       * Test calendar event with no time specified.
     347       *
     348       * @throws coding_exception
     349       */
     350      public function test_feedback_core_calendar_provide_event_action_no_time_specified() {
     351          $this->resetAfterTest();
     352          $this->setAdminUser();
     353  
     354          $course = $this->getDataGenerator()->create_course();
     355          $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
     356          $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
     357  
     358          $factory = new \core_calendar\action_factory();
     359          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory);
     360  
     361          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
     362          $this->assertEquals(get_string('answerquestions', 'feedback'), $actionevent->get_name());
     363          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
     364          $this->assertEquals(1, $actionevent->get_item_count());
     365          $this->assertTrue($actionevent->is_actionable());
     366      }
     367  
     368      /**
     369       * Test calendar event with no time specified, viewed by a different user.
     370       *
     371       * @throws coding_exception
     372       */
     373      public function test_feedback_core_calendar_provide_event_action_no_time_specified_for_user() {
     374          global $DB;
     375  
     376          $this->resetAfterTest();
     377          $this->setAdminUser();
     378  
     379          $course = $this->getDataGenerator()->create_course();
     380          $user = $this->getDataGenerator()->create_user();
     381          $user2 = $this->getDataGenerator()->create_user();
     382          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
     383          $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id, 'manual');
     384  
     385          $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
     386          $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
     387  
     388          $factory = new \core_calendar\action_factory();
     389          $this->setUser($user2);
     390  
     391          // User2 checking their events.
     392          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user2->id);
     393          $this->assertNull($actionevent);
     394  
     395          // User2 checking $user's events.
     396          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user->id);
     397  
     398          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
     399          $this->assertEquals(get_string('answerquestions', 'feedback'), $actionevent->get_name());
     400          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
     401          $this->assertEquals(1, $actionevent->get_item_count());
     402          $this->assertTrue($actionevent->is_actionable());
     403      }
     404  
     405      /**
     406       * A user that can not submit feedback should not have an action.
     407       */
     408      public function test_feedback_core_calendar_provide_event_action_can_not_submit() {
     409          global $DB;
     410  
     411          $this->resetAfterTest();
     412          $this->setAdminUser();
     413  
     414          $user = $this->getDataGenerator()->create_user();
     415          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
     416          $course = $this->getDataGenerator()->create_course();
     417          $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
     418          $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
     419          $cm = get_coursemodule_from_instance('feedback', $feedback->id);
     420          $context = context_module::instance($cm->id);
     421          $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id, 'manual');
     422  
     423          $this->setUser($user);
     424          assign_capability('mod/feedback:complete', CAP_PROHIBIT, $studentrole->id, $context);
     425  
     426          $factory = new \core_calendar\action_factory();
     427          $action = mod_feedback_core_calendar_provide_event_action($event, $factory);
     428  
     429          $this->assertNull($action);
     430      }
     431  
     432      /**
     433       * A user that can not submit feedback should not have an action, viewed by a different user.
     434       */
     435      public function test_feedback_core_calendar_provide_event_action_can_not_submit_for_user() {
     436          global $DB;
     437  
     438          $this->resetAfterTest();
     439          $this->setAdminUser();
     440  
     441          $user = $this->getDataGenerator()->create_user();
     442          $user2 = $this->getDataGenerator()->create_user();
     443          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
     444          $course = $this->getDataGenerator()->create_course();
     445          $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
     446          $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
     447          $cm = get_coursemodule_from_instance('feedback', $feedback->id);
     448          $context = context_module::instance($cm->id);
     449          $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id, 'manual');
     450  
     451          assign_capability('mod/feedback:complete', CAP_PROHIBIT, $studentrole->id, $context);
     452          $factory = new \core_calendar\action_factory();
     453          $this->setUser($user2);
     454  
     455          // User2 checking their events.
     456  
     457          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user2->id);
     458          $this->assertNull($actionevent);
     459  
     460          // User2 checking $user's events.
     461          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user->id);
     462  
     463          $this->assertNull($actionevent);
     464      }
     465  
     466      /**
     467       * A user that has already submitted feedback should not have an action.
     468       */
     469      public function test_feedback_core_calendar_provide_event_action_already_submitted() {
     470          global $DB;
     471  
     472          $this->resetAfterTest();
     473          $this->setAdminUser();
     474  
     475          $user = $this->getDataGenerator()->create_user();
     476          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
     477          $course = $this->getDataGenerator()->create_course();
     478          $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
     479          $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
     480          $cm = get_coursemodule_from_instance('feedback', $feedback->id);
     481          $context = context_module::instance($cm->id);
     482  
     483          $this->setUser($user);
     484  
     485          $record = [
     486              'feedback' => $feedback->id,
     487              'userid' => $user->id,
     488              'timemodified' => time(),
     489              'random_response' => 0,
     490              'anonymous_response' => FEEDBACK_ANONYMOUS_NO,
     491              'courseid' => 0,
     492          ];
     493          $DB->insert_record('feedback_completed', (object) $record);
     494  
     495          $factory = new \core_calendar\action_factory();
     496          $action = mod_feedback_core_calendar_provide_event_action($event, $factory);
     497  
     498          $this->assertNull($action);
     499      }
     500  
     501      /**
     502       * A user that has already submitted feedback should not have an action, viewed by a different user.
     503       */
     504      public function test_feedback_core_calendar_provide_event_action_already_submitted_for_user() {
     505          global $DB;
     506  
     507          $this->resetAfterTest();
     508          $this->setAdminUser();
     509  
     510          $user = $this->getDataGenerator()->create_user();
     511          $user2 = $this->getDataGenerator()->create_user();
     512          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
     513          $course = $this->getDataGenerator()->create_course();
     514          $feedback = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
     515          $event = $this->create_action_event($course->id, $feedback->id, FEEDBACK_EVENT_TYPE_OPEN);
     516          $cm = get_coursemodule_from_instance('feedback', $feedback->id);
     517          $context = context_module::instance($cm->id);
     518  
     519          $this->setUser($user);
     520  
     521          $record = [
     522              'feedback' => $feedback->id,
     523              'userid' => $user->id,
     524              'timemodified' => time(),
     525              'random_response' => 0,
     526              'anonymous_response' => FEEDBACK_ANONYMOUS_NO,
     527              'courseid' => 0,
     528          ];
     529          $DB->insert_record('feedback_completed', (object) $record);
     530  
     531          $factory = new \core_calendar\action_factory();
     532          $this->setUser($user2);
     533  
     534          // User2 checking their events.
     535          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user2->id);
     536          $this->assertNull($actionevent);
     537  
     538          // User2 checking $user's events.
     539          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $user->id);
     540  
     541          $this->assertNull($actionevent);
     542      }
     543  
     544      public function test_feedback_core_calendar_provide_event_action_already_completed() {
     545          $this->resetAfterTest();
     546          set_config('enablecompletion', 1);
     547          $this->setAdminUser();
     548  
     549          // Create the activity.
     550          $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
     551          $feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course->id),
     552              array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
     553  
     554          // Get some additional data.
     555          $cm = get_coursemodule_from_instance('feedback', $feedback->id);
     556  
     557          // Create a calendar event.
     558          $event = $this->create_action_event($course->id, $feedback->id,
     559              \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
     560  
     561          // Mark the activity as completed.
     562          $completion = new completion_info($course);
     563          $completion->set_module_viewed($cm);
     564  
     565          // Create an action factory.
     566          $factory = new \core_calendar\action_factory();
     567  
     568          // Decorate action event.
     569          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory);
     570  
     571          // Ensure result was null.
     572          $this->assertNull($actionevent);
     573      }
     574  
     575      public function test_feedback_core_calendar_provide_event_action_already_completed_for_user() {
     576          $this->resetAfterTest();
     577          set_config('enablecompletion', 1);
     578          $this->setAdminUser();
     579  
     580          // Create the activity.
     581          $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
     582          $feedback = $this->getDataGenerator()->create_module('feedback', array('course' => $course->id),
     583              array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
     584  
     585          // Enrol a student in the course.
     586          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
     587  
     588          // Get some additional data.
     589          $cm = get_coursemodule_from_instance('feedback', $feedback->id);
     590  
     591          // Create a calendar event.
     592          $event = $this->create_action_event($course->id, $feedback->id,
     593              \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
     594  
     595          // Mark the activity as completed for the student.
     596          $completion = new completion_info($course);
     597          $completion->set_module_viewed($cm, $student->id);
     598  
     599          // Create an action factory.
     600          $factory = new \core_calendar\action_factory();
     601  
     602          // Decorate action event for the student.
     603          $actionevent = mod_feedback_core_calendar_provide_event_action($event, $factory, $student->id);
     604  
     605          // Ensure result was null.
     606          $this->assertNull($actionevent);
     607      }
     608  
     609      /**
     610       * Creates an action event.
     611       *
     612       * @param int $courseid The course id.
     613       * @param int $instanceid The feedback id.
     614       * @param string $eventtype The event type. eg. FEEDBACK_EVENT_TYPE_OPEN.
     615       * @return bool|calendar_event
     616       */
     617      private function create_action_event($courseid, $instanceid, $eventtype) {
     618          $event = new stdClass();
     619          $event->name = 'Calendar event';
     620          $event->modulename = 'feedback';
     621          $event->courseid = $courseid;
     622          $event->instance = $instanceid;
     623          $event->type = CALENDAR_EVENT_TYPE_ACTION;
     624          $event->eventtype = $eventtype;
     625          $event->timestart = time();
     626  
     627          return calendar_event::create($event);
     628      }
     629  
     630      /**
     631       * Test the callback responsible for returning the completion rule descriptions.
     632       * This function should work given either an instance of the module (cm_info), such as when checking the active rules,
     633       * or if passed a stdClass of similar structure, such as when checking the the default completion settings for a mod type.
     634       */
     635      public function test_mod_feedback_completion_get_active_rule_descriptions() {
     636          $this->resetAfterTest();
     637          $this->setAdminUser();
     638  
     639          // Two activities, both with automatic completion. One has the 'completionsubmit' rule, one doesn't.
     640          $course = $this->getDataGenerator()->create_course(['enablecompletion' => 2]);
     641          $feedback1 = $this->getDataGenerator()->create_module('feedback', [
     642              'course' => $course->id,
     643              'completion' => 2,
     644              'completionsubmit' => 1
     645          ]);
     646          $feedback2 = $this->getDataGenerator()->create_module('feedback', [
     647              'course' => $course->id,
     648              'completion' => 2,
     649              'completionsubmit' => 0
     650          ]);
     651          $cm1 = cm_info::create(get_coursemodule_from_instance('feedback', $feedback1->id));
     652          $cm2 = cm_info::create(get_coursemodule_from_instance('feedback', $feedback2->id));
     653  
     654          // Data for the stdClass input type.
     655          // This type of input would occur when checking the default completion rules for an activity type, where we don't have
     656          // any access to cm_info, rather the input is a stdClass containing completion and customdata attributes, just like cm_info.
     657          $moddefaults = new stdClass();
     658          $moddefaults->customdata = ['customcompletionrules' => ['completionsubmit' => 1]];
     659          $moddefaults->completion = 2;
     660  
     661          $activeruledescriptions = [get_string('completionsubmit', 'feedback')];
     662          $this->assertEquals(mod_feedback_get_completion_active_rule_descriptions($cm1), $activeruledescriptions);
     663          $this->assertEquals(mod_feedback_get_completion_active_rule_descriptions($cm2), []);
     664          $this->assertEquals(mod_feedback_get_completion_active_rule_descriptions($moddefaults), $activeruledescriptions);
     665          $this->assertEquals(mod_feedback_get_completion_active_rule_descriptions(new stdClass()), []);
     666      }
     667  
     668      /**
     669       * An unknown event should not have min or max restrictions.
     670       */
     671      public function test_get_valid_event_timestart_range_unknown_event() {
     672          global $CFG, $DB;
     673          require_once($CFG->dirroot . "/calendar/lib.php");
     674  
     675          $this->resetAfterTest(true);
     676          $this->setAdminUser();
     677          $generator = $this->getDataGenerator();
     678          $course = $generator->create_course();
     679          $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
     680          $timeopen = time();
     681          $timeclose = $timeopen + DAYSECS;
     682          $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
     683          $feedback->timeopen = $timeopen;
     684          $feedback->timeclose = $timeclose;
     685          $DB->update_record('feedback', $feedback);
     686  
     687          $event = new \calendar_event([
     688              'name' => 'Test event',
     689              'description' => '',
     690              'format' => 1,
     691              'courseid' => $course->id,
     692              'groupid' => 0,
     693              'userid' => 2,
     694              'modulename' => 'feedback',
     695              'instance' => $feedback->id,
     696              'eventtype' => 'SOME UNKNOWN EVENT',
     697              'timestart' => $timeopen,
     698              'timeduration' => 86400,
     699              'visible' => 1
     700          ]);
     701  
     702          list($min, $max) = mod_feedback_core_calendar_get_valid_event_timestart_range($event, $feedback);
     703          $this->assertNull($min);
     704          $this->assertNull($max);
     705      }
     706  
     707      /**
     708       * A FEEDBACK_EVENT_TYPE_OPEN should have a max timestart equal to the activity
     709       * close time.
     710       */
     711      public function test_get_valid_event_timestart_range_event_type_open() {
     712          global $CFG, $DB;
     713          require_once($CFG->dirroot . "/calendar/lib.php");
     714  
     715          $this->resetAfterTest(true);
     716          $this->setAdminUser();
     717          $generator = $this->getDataGenerator();
     718          $course = $generator->create_course();
     719          $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
     720          $timeopen = time();
     721          $timeclose = $timeopen + DAYSECS;
     722          $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
     723          $feedback->timeopen = $timeopen;
     724          $feedback->timeclose = $timeclose;
     725          $DB->update_record('feedback', $feedback);
     726  
     727          $event = new \calendar_event([
     728              'name' => 'Test event',
     729              'description' => '',
     730              'format' => 1,
     731              'courseid' => $course->id,
     732              'groupid' => 0,
     733              'userid' => 2,
     734              'modulename' => 'feedback',
     735              'instance' => $feedback->id,
     736              'eventtype' => FEEDBACK_EVENT_TYPE_OPEN,
     737              'timestart' => $timeopen,
     738              'timeduration' => 86400,
     739              'visible' => 1
     740          ]);
     741  
     742          list($min, $max) = mod_feedback_core_calendar_get_valid_event_timestart_range($event, $feedback);
     743          $this->assertNull($min);
     744          $this->assertEquals($timeclose, $max[0]);
     745          $this->assertNotEmpty($max[1]);
     746      }
     747  
     748      /**
     749       * A FEEDBACK_EVENT_TYPE_OPEN should not have a max timestamp if the activity
     750       * doesn't have a close date.
     751       */
     752      public function test_get_valid_event_timestart_range_event_type_open_no_close() {
     753          global $CFG, $DB;
     754          require_once($CFG->dirroot . "/calendar/lib.php");
     755  
     756          $this->resetAfterTest(true);
     757          $this->setAdminUser();
     758          $generator = $this->getDataGenerator();
     759          $course = $generator->create_course();
     760          $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
     761          $timeopen = time();
     762          $timeclose = $timeopen + DAYSECS;
     763          $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
     764          $feedback->timeopen = $timeopen;
     765          $feedback->timeclose = 0;
     766          $DB->update_record('feedback', $feedback);
     767  
     768          $event = new \calendar_event([
     769              'name' => 'Test event',
     770              'description' => '',
     771              'format' => 1,
     772              'courseid' => $course->id,
     773              'groupid' => 0,
     774              'userid' => 2,
     775              'modulename' => 'feedback',
     776              'instance' => $feedback->id,
     777              'eventtype' => FEEDBACK_EVENT_TYPE_OPEN,
     778              'timestart' => $timeopen,
     779              'timeduration' => 86400,
     780              'visible' => 1
     781          ]);
     782  
     783          list($min, $max) = mod_feedback_core_calendar_get_valid_event_timestart_range($event, $feedback);
     784          $this->assertNull($min);
     785          $this->assertNull($max);
     786      }
     787  
     788      /**
     789       * A FEEDBACK_EVENT_TYPE_CLOSE should have a min timestart equal to the activity
     790       * open time.
     791       */
     792      public function test_get_valid_event_timestart_range_event_type_close() {
     793          global $CFG, $DB;
     794          require_once($CFG->dirroot . "/calendar/lib.php");
     795  
     796          $this->resetAfterTest(true);
     797          $this->setAdminUser();
     798          $generator = $this->getDataGenerator();
     799          $course = $generator->create_course();
     800          $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
     801          $timeopen = time();
     802          $timeclose = $timeopen + DAYSECS;
     803          $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
     804          $feedback->timeopen = $timeopen;
     805          $feedback->timeclose = $timeclose;
     806          $DB->update_record('feedback', $feedback);
     807  
     808          $event = new \calendar_event([
     809              'name' => 'Test event',
     810              'description' => '',
     811              'format' => 1,
     812              'courseid' => $course->id,
     813              'groupid' => 0,
     814              'userid' => 2,
     815              'modulename' => 'feedback',
     816              'instance' => $feedback->id,
     817              'eventtype' => FEEDBACK_EVENT_TYPE_CLOSE,
     818              'timestart' => $timeopen,
     819              'timeduration' => 86400,
     820              'visible' => 1
     821          ]);
     822  
     823          list($min, $max) = mod_feedback_core_calendar_get_valid_event_timestart_range($event, $feedback);
     824          $this->assertEquals($timeopen, $min[0]);
     825          $this->assertNotEmpty($min[1]);
     826          $this->assertNull($max);
     827      }
     828  
     829      /**
     830       * A FEEDBACK_EVENT_TYPE_CLOSE should not have a minimum timestamp if the activity
     831       * doesn't have an open date.
     832       */
     833      public function test_get_valid_event_timestart_range_event_type_close_no_open() {
     834          global $CFG, $DB;
     835          require_once($CFG->dirroot . "/calendar/lib.php");
     836  
     837          $this->resetAfterTest(true);
     838          $this->setAdminUser();
     839          $generator = $this->getDataGenerator();
     840          $course = $generator->create_course();
     841          $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
     842          $timeopen = time();
     843          $timeclose = $timeopen + DAYSECS;
     844          $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
     845          $feedback->timeopen = 0;
     846          $feedback->timeclose = $timeclose;
     847          $DB->update_record('feedback', $feedback);
     848  
     849          $event = new \calendar_event([
     850              'name' => 'Test event',
     851              'description' => '',
     852              'format' => 1,
     853              'courseid' => $course->id,
     854              'groupid' => 0,
     855              'userid' => 2,
     856              'modulename' => 'feedback',
     857              'instance' => $feedback->id,
     858              'eventtype' => FEEDBACK_EVENT_TYPE_CLOSE,
     859              'timestart' => $timeopen,
     860              'timeduration' => 86400,
     861              'visible' => 1
     862          ]);
     863  
     864          list($min, $max) = mod_feedback_core_calendar_get_valid_event_timestart_range($event, $feedback);
     865          $this->assertNull($min);
     866          $this->assertNull($max);
     867      }
     868  
     869      /**
     870       * An unkown event type should not change the feedback instance.
     871       */
     872      public function test_mod_feedback_core_calendar_event_timestart_updated_unknown_event() {
     873          global $CFG, $DB;
     874          require_once($CFG->dirroot . "/calendar/lib.php");
     875  
     876          $this->resetAfterTest(true);
     877          $this->setAdminUser();
     878          $generator = $this->getDataGenerator();
     879          $course = $generator->create_course();
     880          $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
     881          $timeopen = time();
     882          $timeclose = $timeopen + DAYSECS;
     883          $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
     884          $feedback->timeopen = $timeopen;
     885          $feedback->timeclose = $timeclose;
     886          $DB->update_record('feedback', $feedback);
     887  
     888          // Create a valid event.
     889          $event = new \calendar_event([
     890              'name' => 'Test event',
     891              'description' => '',
     892              'format' => 1,
     893              'courseid' => $course->id,
     894              'groupid' => 0,
     895              'userid' => 2,
     896              'modulename' => 'feedback',
     897              'instance' => $feedback->id,
     898              'eventtype' => FEEDBACK_EVENT_TYPE_OPEN . "SOMETHING ELSE",
     899              'timestart' => 1,
     900              'timeduration' => 86400,
     901              'visible' => 1
     902          ]);
     903  
     904          mod_feedback_core_calendar_event_timestart_updated($event, $feedback);
     905  
     906          $feedback = $DB->get_record('feedback', ['id' => $feedback->id]);
     907          $this->assertEquals($timeopen, $feedback->timeopen);
     908          $this->assertEquals($timeclose, $feedback->timeclose);
     909      }
     910  
     911      /**
     912       * A FEEDBACK_EVENT_TYPE_OPEN event should update the timeopen property of
     913       * the feedback activity.
     914       */
     915      public function test_mod_feedback_core_calendar_event_timestart_updated_open_event() {
     916          global $CFG, $DB;
     917          require_once($CFG->dirroot . "/calendar/lib.php");
     918  
     919          $this->resetAfterTest(true);
     920          $this->setAdminUser();
     921          $generator = $this->getDataGenerator();
     922          $course = $generator->create_course();
     923          $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
     924          $timeopen = time();
     925          $timeclose = $timeopen + DAYSECS;
     926          $timemodified = 1;
     927          $newtimeopen = $timeopen - DAYSECS;
     928          $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
     929          $feedback->timeopen = $timeopen;
     930          $feedback->timeclose = $timeclose;
     931          $feedback->timemodified = $timemodified;
     932          $DB->update_record('feedback', $feedback);
     933  
     934          // Create a valid event.
     935          $event = new \calendar_event([
     936              'name' => 'Test event',
     937              'description' => '',
     938              'format' => 1,
     939              'courseid' => $course->id,
     940              'groupid' => 0,
     941              'userid' => 2,
     942              'modulename' => 'feedback',
     943              'instance' => $feedback->id,
     944              'eventtype' => FEEDBACK_EVENT_TYPE_OPEN,
     945              'timestart' => $newtimeopen,
     946              'timeduration' => 86400,
     947              'visible' => 1
     948          ]);
     949  
     950          mod_feedback_core_calendar_event_timestart_updated($event, $feedback);
     951  
     952          $feedback = $DB->get_record('feedback', ['id' => $feedback->id]);
     953          // Ensure the timeopen property matches the event timestart.
     954          $this->assertEquals($newtimeopen, $feedback->timeopen);
     955          // Ensure the timeclose isn't changed.
     956          $this->assertEquals($timeclose, $feedback->timeclose);
     957          // Ensure the timemodified property has been changed.
     958          $this->assertNotEquals($timemodified, $feedback->timemodified);
     959      }
     960  
     961      /**
     962       * A FEEDBACK_EVENT_TYPE_CLOSE event should update the timeclose property of
     963       * the feedback activity.
     964       */
     965      public function test_mod_feedback_core_calendar_event_timestart_updated_close_event() {
     966          global $CFG, $DB;
     967          require_once($CFG->dirroot . "/calendar/lib.php");
     968  
     969          $this->resetAfterTest(true);
     970          $this->setAdminUser();
     971          $generator = $this->getDataGenerator();
     972          $course = $generator->create_course();
     973          $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
     974          $timeopen = time();
     975          $timeclose = $timeopen + DAYSECS;
     976          $timemodified = 1;
     977          $newtimeclose = $timeclose + DAYSECS;
     978          $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
     979          $feedback->timeopen = $timeopen;
     980          $feedback->timeclose = $timeclose;
     981          $feedback->timemodified = $timemodified;
     982          $DB->update_record('feedback', $feedback);
     983  
     984          // Create a valid event.
     985          $event = new \calendar_event([
     986              'name' => 'Test event',
     987              'description' => '',
     988              'format' => 1,
     989              'courseid' => $course->id,
     990              'groupid' => 0,
     991              'userid' => 2,
     992              'modulename' => 'feedback',
     993              'instance' => $feedback->id,
     994              'eventtype' => FEEDBACK_EVENT_TYPE_CLOSE,
     995              'timestart' => $newtimeclose,
     996              'timeduration' => 86400,
     997              'visible' => 1
     998          ]);
     999  
    1000          mod_feedback_core_calendar_event_timestart_updated($event, $feedback);
    1001  
    1002          $feedback = $DB->get_record('feedback', ['id' => $feedback->id]);
    1003          // Ensure the timeclose property matches the event timestart.
    1004          $this->assertEquals($newtimeclose, $feedback->timeclose);
    1005          // Ensure the timeopen isn't changed.
    1006          $this->assertEquals($timeopen, $feedback->timeopen);
    1007          // Ensure the timemodified property has been changed.
    1008          $this->assertNotEquals($timemodified, $feedback->timemodified);
    1009      }
    1010  
    1011      /**
    1012       * If a student somehow finds a way to update the calendar event
    1013       * then the callback should not be executed to update the activity
    1014       * properties as well because that would be a security issue.
    1015       */
    1016      public function test_student_role_cant_update_time_close_event() {
    1017          global $CFG, $DB;
    1018          require_once($CFG->dirroot . '/calendar/lib.php');
    1019  
    1020          $this->resetAfterTest();
    1021          $this->setAdminUser();
    1022  
    1023          $generator = $this->getDataGenerator();
    1024          $user = $generator->create_user();
    1025          $course = $generator->create_course();
    1026          $context = context_course::instance($course->id);
    1027          $roleid = $generator->create_role();
    1028          $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
    1029          $timeopen = time();
    1030          $timeclose = $timeopen + DAYSECS;
    1031          $timemodified = 1;
    1032          $newtimeclose = $timeclose + DAYSECS;
    1033          $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
    1034          $feedback->timeopen = $timeopen;
    1035          $feedback->timeclose = $timeclose;
    1036          $feedback->timemodified = $timemodified;
    1037          $DB->update_record('feedback', $feedback);
    1038  
    1039          $generator->enrol_user($user->id, $course->id, 'student');
    1040          $generator->role_assign($roleid, $user->id, $context->id);
    1041  
    1042          // Create a valid event.
    1043          $event = new \calendar_event([
    1044              'name' => 'Test event',
    1045              'description' => '',
    1046              'format' => 1,
    1047              'courseid' => $course->id,
    1048              'groupid' => 0,
    1049              'userid' => $user->id,
    1050              'modulename' => 'feedback',
    1051              'instance' => $feedback->id,
    1052              'eventtype' => FEEDBACK_EVENT_TYPE_CLOSE,
    1053              'timestart' => $newtimeclose,
    1054              'timeduration' => 86400,
    1055              'visible' => 1
    1056          ]);
    1057  
    1058          assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
    1059          assign_capability('moodle/course:manageactivities', CAP_PROHIBIT, $roleid, $context, true);
    1060  
    1061          $this->setUser($user);
    1062  
    1063          mod_feedback_core_calendar_event_timestart_updated($event, $feedback);
    1064  
    1065          $newfeedback = $DB->get_record('feedback', ['id' => $feedback->id]);
    1066          // The activity shouldn't have been updated because the user
    1067          // doesn't have permissions to do it.
    1068          $this->assertEquals($timeclose, $newfeedback->timeclose);
    1069      }
    1070  
    1071      /**
    1072       * The activity should update if a teacher modifies the calendar
    1073       * event.
    1074       */
    1075      public function test_teacher_role_can_update_time_close_event() {
    1076          global $CFG, $DB;
    1077          require_once($CFG->dirroot . '/calendar/lib.php');
    1078  
    1079          $this->resetAfterTest();
    1080          $this->setAdminUser();
    1081  
    1082          $generator = $this->getDataGenerator();
    1083          $user = $generator->create_user();
    1084          $course = $generator->create_course();
    1085          $context = context_course::instance($course->id);
    1086          $roleid = $generator->create_role();
    1087          $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
    1088          $timeopen = time();
    1089          $timeclose = $timeopen + DAYSECS;
    1090          $timemodified = 1;
    1091          $newtimeclose = $timeclose + DAYSECS;
    1092          $feedback = $feedbackgenerator->create_instance(['course' => $course->id]);
    1093          $feedback->timeopen = $timeopen;
    1094          $feedback->timeclose = $timeclose;
    1095          $feedback->timemodified = $timemodified;
    1096          $DB->update_record('feedback', $feedback);
    1097  
    1098          $generator->enrol_user($user->id, $course->id, 'teacher');
    1099          $generator->role_assign($roleid, $user->id, $context->id);
    1100  
    1101          // Create a valid event.
    1102          $event = new \calendar_event([
    1103              'name' => 'Test event',
    1104              'description' => '',
    1105              'format' => 1,
    1106              'courseid' => $course->id,
    1107              'groupid' => 0,
    1108              'userid' => $user->id,
    1109              'modulename' => 'feedback',
    1110              'instance' => $feedback->id,
    1111              'eventtype' => FEEDBACK_EVENT_TYPE_CLOSE,
    1112              'timestart' => $newtimeclose,
    1113              'timeduration' => 86400,
    1114              'visible' => 1
    1115          ]);
    1116  
    1117          assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
    1118          assign_capability('moodle/course:manageactivities', CAP_ALLOW, $roleid, $context, true);
    1119  
    1120          $this->setUser($user);
    1121  
    1122          $sink = $this->redirectEvents();
    1123  
    1124          mod_feedback_core_calendar_event_timestart_updated($event, $feedback);
    1125  
    1126          $triggeredevents = $sink->get_events();
    1127          $moduleupdatedevents = array_filter($triggeredevents, function($e) {
    1128              return is_a($e, 'core\event\course_module_updated');
    1129          });
    1130  
    1131          $newfeedback = $DB->get_record('feedback', ['id' => $feedback->id]);
    1132          // The activity should have been updated because the user
    1133          // has permissions to do it.
    1134          $this->assertEquals($newtimeclose, $newfeedback->timeclose);
    1135          // A course_module_updated event should be fired if the module
    1136          // was successfully modified.
    1137          $this->assertNotEmpty($moduleupdatedevents);
    1138      }
    1139  
    1140      /**
    1141       * A user who does not have capabilities to add events to the calendar should be able to create an feedback.
    1142       */
    1143      public function test_creation_with_no_calendar_capabilities() {
    1144          $this->resetAfterTest();
    1145          $course = self::getDataGenerator()->create_course();
    1146          $context = context_course::instance($course->id);
    1147          $user = self::getDataGenerator()->create_and_enrol($course, 'editingteacher');
    1148          $roleid = self::getDataGenerator()->create_role();
    1149          self::getDataGenerator()->role_assign($roleid, $user->id, $context->id);
    1150          assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true);
    1151          $generator = self::getDataGenerator()->get_plugin_generator('mod_feedback');
    1152          // Create an instance as a user without the calendar capabilities.
    1153          $this->setUser($user);
    1154          $time = time();
    1155          $params = array(
    1156              'course' => $course->id,
    1157              'timeopen' => $time + 200,
    1158              'timeclose' => $time + 2000,
    1159          );
    1160          $generator->create_instance($params);
    1161      }
    1162  }