first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+488
View File
@@ -0,0 +1,488 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* External function test for get_attempts.
*
* @package mod_h5pactivity
* @category external
* @since Moodle 3.9
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_h5pactivity\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
use mod_h5pactivity\local\manager;
use core_external\external_api;
use externallib_advanced_testcase;
/**
* External function test for get_attempts.
*
* @package mod_h5pactivity
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class get_attempts_test extends externallib_advanced_testcase {
/**
* Test the behaviour of get_attempts.
*
* @dataProvider execute_data
* @param int $grademethod the activity grading method
* @param string $loginuser the user which calls the webservice
* @param string|null $participant the user to get the data
* @param bool $createattempts if the student user has attempts created
* @param int|null $count the expected number of attempts returned (null for exception)
*/
public function test_execute(int $grademethod, string $loginuser, ?string $participant,
bool $createattempts, ?int $count): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$activity = $this->getDataGenerator()->create_module('h5pactivity',
['course' => $course, 'enabletracking' => 1, 'grademethod' => $grademethod]);
$manager = manager::create_from_instance($activity);
$cm = $manager->get_coursemodule();
// Prepare users: 1 teacher, 2 students, 1 unenroled user.
$users = [
'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'),
'student' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
'other' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
'noenrolled' => $this->getDataGenerator()->create_user(),
];
$generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
if ($createattempts) {
$user = $users['student'];
$params = ['cmid' => $cm->id, 'userid' => $user->id];
$generator->create_content($activity, $params);
$generator->create_content($activity, $params);
}
// Create another user with 2 attempts to validate no cross attempts are returned.
$user = $users['other'];
$params = ['cmid' => $cm->id, 'userid' => $user->id];
$generator->create_content($activity, $params);
$generator->create_content($activity, $params);
// Execute external method.
$this->setUser($users[$loginuser]);
$userids = ($participant) ? [$users[$participant]->id] : [];
$checkuserid = ($participant) ? $users[$participant]->id : $users[$loginuser]->id;
$result = get_attempts::execute($activity->id, $userids);
$result = external_api::clean_returnvalue(
get_attempts::execute_returns(),
$result
);
// Validate general structure.
$this->assertArrayHasKey('activityid', $result);
$this->assertArrayHasKey('usersattempts', $result);
$this->assertArrayHasKey('warnings', $result);
$this->assertEquals($activity->id, $result['activityid']);
if ($count === null) {
$this->assertCount(1, $result['warnings']);
$this->assertCount(0, $result['usersattempts']);
return;
}
$this->assertCount(0, $result['warnings']);
$this->assertCount(1, $result['usersattempts']);
$userattempts = $result['usersattempts'][0];
$this->assertEquals($checkuserid, $userattempts['userid']);
// Validate scored attempts.
if ($grademethod == manager::GRADEMANUAL || $grademethod == manager::GRADEAVERAGEATTEMPT || $count == 0) {
$this->assertArrayNotHasKey('scored', $userattempts);
} else {
$this->assertArrayHasKey('scored', $userattempts);
list($dbgrademethod, $title) = $manager->get_selected_attempt();
$this->assertEquals($grademethod, $dbgrademethod);
$this->assertEquals($grademethod, $userattempts['scored']['grademethod']);
$this->assertEquals($title, $userattempts['scored']['title']);
$this->assertCount(1, $userattempts['scored']['attempts']);
}
// Validate returned attempts.
$this->assertCount($count, $userattempts['attempts']);
foreach ($userattempts['attempts'] as $attempt) {
$this->assertArrayHasKey('id', $attempt);
$this->assertEquals($checkuserid, $attempt['userid']);
$this->assertArrayHasKey('timecreated', $attempt);
$this->assertArrayHasKey('timemodified', $attempt);
$this->assertArrayHasKey('attempt', $attempt);
$this->assertArrayHasKey('rawscore', $attempt);
$this->assertArrayHasKey('maxscore', $attempt);
$this->assertArrayHasKey('duration', $attempt);
$this->assertArrayHasKey('completion', $attempt);
$this->assertArrayHasKey('success', $attempt);
$this->assertArrayHasKey('scaled', $attempt);
}
}
/**
* Data provider for the test_execute tests.
*
* @return array
*/
public function execute_data(): array {
return [
// Teacher checking a user with attempts.
'Manual grade, Teacher asking participant with attempts' => [
manager::GRADEMANUAL, 'editingteacher', 'student', true, 2
],
'Highest grade, Teacher asking participant with attempts' => [
manager::GRADEHIGHESTATTEMPT, 'editingteacher', 'student', true, 2
],
'Average grade, Teacher asking participant with attempts' => [
manager::GRADEAVERAGEATTEMPT, 'editingteacher', 'student', true, 2
],
'Last grade, Teacher asking participant with attempts' => [
manager::GRADELASTATTEMPT, 'editingteacher', 'student', true, 2
],
'First grade, Teacher asking participant with attempts' => [
manager::GRADEFIRSTATTEMPT, 'editingteacher', 'student', true, 2
],
// Teacher checking a user without attempts.
'Manual grade, Teacher asking participant without attempts' => [
manager::GRADEMANUAL, 'editingteacher', 'student', false, 0
],
'Highest grade, Teacher asking participant without attempts' => [
manager::GRADEHIGHESTATTEMPT, 'editingteacher', 'student', false, 0
],
'Average grade, Teacher asking participant without attempts' => [
manager::GRADEAVERAGEATTEMPT, 'editingteacher', 'student', false, 0
],
'Last grade, Teacher asking participant without attempts' => [
manager::GRADELASTATTEMPT, 'editingteacher', 'student', false, 0
],
'First grade, Teacher asking participant without attempts' => [
manager::GRADEFIRSTATTEMPT, 'editingteacher', 'student', false, 0
],
// Student checking own attempts specifying userid.
'Manual grade, check same user attempts report with attempts' => [
manager::GRADEMANUAL, 'student', 'student', true, 2
],
'Highest grade, check same user attempts report with attempts' => [
manager::GRADEHIGHESTATTEMPT, 'student', 'student', true, 2
],
'Average grade, check same user attempts report with attempts' => [
manager::GRADEAVERAGEATTEMPT, 'student', 'student', true, 2
],
'Last grade, check same user attempts report with attempts' => [
manager::GRADELASTATTEMPT, 'student', 'student', true, 2
],
'First grade, check same user attempts report with attempts' => [
manager::GRADEFIRSTATTEMPT, 'student', 'student', true, 2
],
// Student checking own attempts.
'Manual grade, check own attempts report with attempts' => [
manager::GRADEMANUAL, 'student', null, true, 2
],
'Highest grade, check own attempts report with attempts' => [
manager::GRADEHIGHESTATTEMPT, 'student', null, true, 2
],
'Average grade, check own attempts report with attempts' => [
manager::GRADEAVERAGEATTEMPT, 'student', null, true, 2
],
'Last grade, check own attempts report with attempts' => [
manager::GRADELASTATTEMPT, 'student', null, true, 2
],
'First grade, check own attempts report with attempts' => [
manager::GRADEFIRSTATTEMPT, 'student', null, true, 2
],
// Student checking own report without attempts.
'Manual grade, check own attempts report without attempts' => [
manager::GRADEMANUAL, 'student', 'student', false, 0
],
'Highest grade, check own attempts report without attempts' => [
manager::GRADEHIGHESTATTEMPT, 'student', 'student', false, 0
],
'Average grade, check own attempts report without attempts' => [
manager::GRADEAVERAGEATTEMPT, 'student', 'student', false, 0
],
'Last grade, check own attempts report without attempts' => [
manager::GRADELASTATTEMPT, 'student', 'student', false, 0
],
'First grade, check own attempts report without attempts' => [
manager::GRADEFIRSTATTEMPT, 'student', 'student', false, 0
],
// Student trying to get another user attempts.
'Manual grade, student trying to stalk another student' => [
manager::GRADEMANUAL, 'student', 'other', false, null
],
'Highest grade, student trying to stalk another student' => [
manager::GRADEHIGHESTATTEMPT, 'student', 'other', false, null
],
'Average grade, student trying to stalk another student' => [
manager::GRADEAVERAGEATTEMPT, 'student', 'other', false, null
],
'Last grade, student trying to stalk another student' => [
manager::GRADELASTATTEMPT, 'student', 'other', false, null
],
'First grade, student trying to stalk another student' => [
manager::GRADEFIRSTATTEMPT, 'student', 'other', false, null
],
// Teacher trying to get a non enroled user attempts.
'Manual grade, teacher trying to get an non enrolled user attempts' => [
manager::GRADEMANUAL, 'editingteacher', 'noenrolled', false, null
],
'Highest grade, teacher trying to get an non enrolled user attempts' => [
manager::GRADEHIGHESTATTEMPT, 'editingteacher', 'noenrolled', false, null
],
'Average grade, teacher trying to get an non enrolled user attempts' => [
manager::GRADEAVERAGEATTEMPT, 'editingteacher', 'noenrolled', false, null
],
'Last grade, teacher trying to get an non enrolled user attempts' => [
manager::GRADELASTATTEMPT, 'editingteacher', 'noenrolled', false, null
],
'First grade, teacher trying to get an non enrolled user attempts' => [
manager::GRADEFIRSTATTEMPT, 'editingteacher', 'noenrolled', false, null
],
// Student trying to get a non enroled user attempts.
'Manual grade, student trying to get an non enrolled user attempts' => [
manager::GRADEMANUAL, 'student', 'noenrolled', false, null
],
'Highest grade, student trying to get an non enrolled user attempts' => [
manager::GRADEHIGHESTATTEMPT, 'student', 'noenrolled', false, null
],
'Average grade, student trying to get an non enrolled user attempts' => [
manager::GRADEAVERAGEATTEMPT, 'student', 'noenrolled', false, null
],
'Last grade, student trying to get an non enrolled user attempts' => [
manager::GRADELASTATTEMPT, 'student', 'noenrolled', false, null
],
'First grade, student trying to get an non enrolled user attempts' => [
manager::GRADEFIRSTATTEMPT, 'student', 'noenrolled', false, null
],
];
}
/**
* Test the behaviour of get_attempts when tracking is not enabled.
*
*/
public function test_execute_no_tracking(): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$activity = $this->getDataGenerator()->create_module('h5pactivity',
['course' => $course, 'enabletracking' => 0]);
$manager = manager::create_from_instance($activity);
$cm = $manager->get_coursemodule();
// Prepare users: 1 teacher, 1 student.
$users = [
'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'),
'student' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
];
// Execute external method.
$this->setUser($users['editingteacher']);
$result = get_attempts::execute($activity->id, [$users['student']->id]);
$result = external_api::clean_returnvalue(
get_attempts::execute_returns(),
$result
);
$this->assertCount(1, $result['warnings']);
$this->assertCount(0, $result['usersattempts']);
}
/**
* Test the behaviour of get_attempts when own review is not allowed.
*
*/
public function test_execute_no_own_review(): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$activity = $this->getDataGenerator()->create_module('h5pactivity',
['course' => $course, 'enabletracking' => 1, 'reviewmode' => manager::REVIEWNONE]);
$manager = manager::create_from_instance($activity);
$cm = $manager->get_coursemodule();
// Prepare users: 1 student.
$users = [
'student' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
];
// Execute external method.
$this->setUser($users['student']);
$result = get_attempts::execute($activity->id);
$result = external_api::clean_returnvalue(
get_attempts::execute_returns(),
$result
);
$this->assertCount(1, $result['warnings']);
$this->assertCount(0, $result['usersattempts']);
}
/**
* Test the behaviour of get_attempts getting more than one user at once.
*
* @dataProvider execute_multipleusers_data
* @param string $loginuser the user which calls the webservice
* @param string[] $participants the users to get the data
* @param string[] $warnings the expected users with warnings
* @param string[] $resultusers expected users in the resultusers
*/
public function test_execute_multipleusers(string $loginuser, array $participants,
array $warnings, array $resultusers): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$activity = $this->getDataGenerator()->create_module('h5pactivity',
['course' => $course]);
$manager = manager::create_from_instance($activity);
$cm = $manager->get_coursemodule();
// Prepare users: 1 teacher, 2 students with attempts, 1 student without, 1 no enrolled.
$users = [
'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'),
'student1' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
'student2' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
'noattempts' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
'noenrolled' => $this->getDataGenerator()->create_user(),
];
// Generate attempts (student1 with 1 attempt, student2 with 2).
$generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
$user = $users['student1'];
$params = ['cmid' => $cm->id, 'userid' => $user->id];
$generator->create_content($activity, $params);
$user = $users['student2'];
$params = ['cmid' => $cm->id, 'userid' => $user->id];
$generator->create_content($activity, $params);
$generator->create_content($activity, $params);
$countattempts = [
$users['editingteacher']->id => 0,
$users['student1']->id => 1,
$users['student2']->id => 2,
$users['noattempts']->id => 0,
$users['noenrolled']->id => 0,
];
// Execute external method.
$this->setUser($users[$loginuser]);
$userids = [];
foreach ($participants as $participant) {
$userids[] = $users[$participant]->id;
}
$result = get_attempts::execute($activity->id, $userids);
$result = external_api::clean_returnvalue(
get_attempts::execute_returns(),
$result
);
$this->assertCount(count($warnings), $result['warnings']);
$this->assertCount(count($resultusers), $result['usersattempts']);
$expectedwarnings = [];
foreach ($warnings as $warninguser) {
$id = $users[$warninguser]->id;
$expectedwarnings[$id] = $warninguser;
}
foreach ($result['warnings'] as $warning) {
$this->assertEquals('user', $warning['item']);
$this->assertEquals(1, $warning['warningcode']);
$this->assertArrayHasKey($warning['itemid'], $expectedwarnings);
}
$expectedusers = [];
foreach ($resultusers as $resultuser) {
$id = $users[$resultuser]->id;
$expectedusers[$id] = $resultuser;
}
foreach ($result['usersattempts'] as $usersattempts) {
$this->assertArrayHasKey('userid', $usersattempts);
$userid = $usersattempts['userid'];
$this->assertArrayHasKey($userid, $expectedusers);
$this->assertCount($countattempts[$userid], $usersattempts['attempts']);
if ($countattempts[$userid]) {
$this->assertArrayHasKey('scored', $usersattempts);
}
}
}
/**
* Data provider for the test_execute_multipleusers.
*
* @return array
*/
public function execute_multipleusers_data(): array {
return [
// Teacher checks.
'Teacher checking students with attempts' => [
'editingteacher', ['student1', 'student2'], [], ['student1', 'student2']
],
'Teacher checking one student with atempts and one not' => [
'editingteacher', ['student1', 'noattempts'], [], ['student1', 'noattempts']
],
'Teacher checking no students' => [
'editingteacher', [], [], ['editingteacher']
],
'Teacher checking one student and a no enrolled user' => [
'editingteacher', ['student1', 'noenrolled'], ['noenrolled'], ['student1']
],
// Student checks.
'Student checking self attempts and another user' => [
'student1', ['student1', 'student2'], ['student2'], ['student1']
],
'Student checking no students' => [
'student1', [], [], ['student1']
],
'Student checking self attempts and a no enrolled user' => [
'student1', ['student1', 'noenrolled'], ['noenrolled'], ['student1']
],
];
}
}
@@ -0,0 +1,201 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* External function test for get_h5pactivities_by_courses.
*
* @package mod_h5pactivity
* @category external
* @since Moodle 3.9
* @copyright 2020 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_h5pactivity\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
use core_external\external_api;
use externallib_advanced_testcase;
use context_module;
/**
* External function test for get_h5pactivities_by_courses.
*
* @package mod_h5pactivity
* @copyright 2020 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class get_h5pactivities_by_courses_test extends externallib_advanced_testcase {
/**
* Test test_get_h5pactivities_by_courses user student.
*/
public function test_get_h5pactivities_by_courses(): void {
global $CFG, $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Create 2 courses.
// Course 1 -> 2 activities with H5P files package without deploy.
// Course 2 -> 1 activity with H5P file package deployed.
$course1 = $this->getDataGenerator()->create_course();
$params = [
'course' => $course1->id,
'packagefilepath' => $CFG->dirroot.'/h5p/tests/fixtures/filltheblanks.h5p',
'introformat' => 1
];
$activities[] = $this->getDataGenerator()->create_module('h5pactivity', $params);
// Add filename and contextid to make easier the asserts.
$activities[0]->filename = 'filltheblanks.h5p';
$context = context_module::instance($activities[0]->cmid);
$activities[0]->contextid = $context->id;
$params = [
'course' => $course1->id,
'packagefilepath' => $CFG->dirroot.'/h5p/tests/fixtures/greeting-card.h5p',
'introformat' => 1
];
$activities[] = $this->getDataGenerator()->create_module('h5pactivity', $params);
// Add filename and contextid to make easier the asserts.
$activities[1]->filename = 'greeting-card.h5p';
$context = context_module::instance($activities[1]->cmid);
$activities[1]->contextid = $context->id;
$course2 = $this->getDataGenerator()->create_course();
$params = [
'course' => $course2->id,
'packagefilepath' => $CFG->dirroot.'/h5p/tests/fixtures/guess-the-answer.h5p',
'introformat' => 1
];
$activities[] = $this->getDataGenerator()->create_module('h5pactivity', $params);
$activities[2]->filename = 'guess-the-answer.h5p';
$context = context_module::instance($activities[2]->cmid);
$activities[2]->contextid = $context->id;
// Create a fake deploy H5P file.
$generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
$deployedfile = $generator->create_export_file($activities[2]->filename, $context->id, 'mod_h5pactivity', 'package');
// Create a user and enrol as student in both courses.
$user = $this->getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', ['shortname' => 'student']);
$maninstance1 = $DB->get_record('enrol', ['courseid' => $course1->id, 'enrol' => 'manual'], '*', MUST_EXIST);
$maninstance2 = $DB->get_record('enrol', ['courseid' => $course2->id, 'enrol' => 'manual'], '*', MUST_EXIST);
$manual = enrol_get_plugin('manual');
$manual->enrol_user($maninstance1, $user->id, $studentrole->id);
$manual->enrol_user($maninstance2, $user->id, $studentrole->id);
// Set admin settings.
set_config('enablesavestate', 1, 'mod_h5pactivity');
set_config('savestatefreq', 120, 'mod_h5pactivity');
// Check the activities returned by the first course.
$this->setUser($user);
$courseids = [$course1->id];
$result = get_h5pactivities_by_courses::execute($courseids);
$result = external_api::clean_returnvalue(get_h5pactivities_by_courses::execute_returns(), $result);
$this->assertCount(0, $result['warnings']);
$this->assertCount(2, $result['h5pactivities']);
$this->assert_activities($activities, $result);
$this->assertNotContains('deployedfile', $result['h5pactivities'][0]);
$this->assertNotContains('deployedfile', $result['h5pactivities'][1]);
$this->assertEquals(1, $result['h5pglobalsettings']['enablesavestate']);
$this->assertEquals(120, $result['h5pglobalsettings']['savestatefreq']);
// Call the external function without passing course id.
// Expected result, all the courses, course1 and course2.
$result = get_h5pactivities_by_courses::execute([]);
$result = external_api::clean_returnvalue(get_h5pactivities_by_courses::execute_returns(), $result);
$this->assertCount(0, $result['warnings']);
$this->assertCount(3, $result['h5pactivities']);
// We need to sort the $result by id.
// Because we are not sure how it is ordered with more than one course.
array_multisort(array_map(function($element) {
return $element['id'];
}, $result['h5pactivities']), SORT_ASC, $result['h5pactivities']);
$this->assert_activities($activities, $result);
$this->assertNotContains('deployedfile', $result['h5pactivities'][0]);
$this->assertNotContains('deployedfile', $result['h5pactivities'][1]);
// Only the activity from the second course has been deployed.
$this->assertEquals($deployedfile['filename'], $result['h5pactivities'][2]['deployedfile']['filename']);
$this->assertEquals($deployedfile['filepath'], $result['h5pactivities'][2]['deployedfile']['filepath']);
$this->assertEquals($deployedfile['filesize'], $result['h5pactivities'][2]['deployedfile']['filesize']);
$this->assertEquals($deployedfile['timemodified'], $result['h5pactivities'][2]['deployedfile']['timemodified']);
$this->assertEquals($deployedfile['mimetype'], $result['h5pactivities'][2]['deployedfile']['mimetype']);
$this->assertEquals($deployedfile['fileurl'], $result['h5pactivities'][2]['deployedfile']['fileurl']);
$this->assertEquals(1, $result['h5pglobalsettings']['enablesavestate']);
$this->assertEquals(120, $result['h5pglobalsettings']['savestatefreq']);
// Unenrol user from second course.
$manual->unenrol_user($maninstance2, $user->id);
// Remove the last activity from the array.
array_pop($activities);
// Disable save state.
set_config('enablesavestate', 0, 'mod_h5pactivity');
// Call the external function without passing course id.
$result = get_h5pactivities_by_courses::execute([]);
$result = external_api::clean_returnvalue(get_h5pactivities_by_courses::execute_returns(), $result);
$this->assertCount(0, $result['warnings']);
$this->assertCount(2, $result['h5pactivities']);
$this->assert_activities($activities, $result);
$this->assertEquals(0, $result['h5pglobalsettings']['enablesavestate']);
$this->assertNotContains('savestatefreq', $result['h5pglobalsettings']);
// Call for the second course we unenrolled the user from, expected warning.
$result = get_h5pactivities_by_courses::execute([$course2->id]);
$result = external_api::clean_returnvalue(get_h5pactivities_by_courses::execute_returns(), $result);
$this->assertCount(1, $result['warnings']);
$this->assertEquals('1', $result['warnings'][0]['warningcode']);
$this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
}
/**
* Create a scenario to use into the tests.
*
* @param array $activities list of H5P activities.
* @param array $result list of H5P activities by WS.
* @return void
*/
protected function assert_activities(array $activities, array $result): void {
$total = count($result['h5pactivities']);
for ($i = 0; $i < $total; $i++) {
$this->assertEquals($activities[$i]->id, $result['h5pactivities'][$i]['id']);
$this->assertEquals($activities[$i]->course, $result['h5pactivities'][$i]['course']);
$this->assertEquals($activities[$i]->name, $result['h5pactivities'][$i]['name']);
$this->assertEquals($activities[$i]->timecreated, $result['h5pactivities'][$i]['timecreated']);
$this->assertEquals($activities[$i]->timemodified, $result['h5pactivities'][$i]['timemodified']);
$this->assertEquals($activities[$i]->intro, $result['h5pactivities'][$i]['intro']);
$this->assertEquals($activities[$i]->introformat, $result['h5pactivities'][$i]['introformat']);
$this->assertEquals([], $result['h5pactivities'][$i]['introfiles']);
$this->assertEquals($activities[$i]->grade, $result['h5pactivities'][$i]['grade']);
$this->assertEquals($activities[$i]->displayoptions, $result['h5pactivities'][$i]['displayoptions']);
$this->assertEquals($activities[$i]->enabletracking, $result['h5pactivities'][$i]['enabletracking']);
$this->assertEquals($activities[$i]->grademethod, $result['h5pactivities'][$i]['grademethod']);
$this->assertEquals($activities[$i]->cmid, $result['h5pactivities'][$i]['coursemodule']);
$this->assertEquals($activities[$i]->contextid, $result['h5pactivities'][$i]['context']);
$this->assertEquals($activities[$i]->filename, $result['h5pactivities'][$i]['package'][0]['filename']);
}
}
}
@@ -0,0 +1,137 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* External function test for get_h5pactivity_access_information.
*
* @package mod_h5pactivity
* @category external
* @since Moodle 3.9
* @copyright 2020 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_h5pactivity\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
use dml_missing_record_exception;
use core_external\external_api;
use externallib_advanced_testcase;
/**
* External function test for get_h5pactivity_access_information.
*
* @package mod_h5pactivity
* @copyright 2020 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class get_h5pactivity_access_information_test extends externallib_advanced_testcase {
/**
* Test the behaviour of get_h5pactivity_access_information().
*
* @dataProvider get_h5pactivity_access_information_data
* @param string $role user role in course
* @param int $enabletracking if tracking is enabled
* @param array $enabledcaps capabilities enabled
*/
public function test_get_h5pactivity_access_information(string $role, int $enabletracking, array $enabledcaps): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$activity = $this->getDataGenerator()->create_module('h5pactivity',
[
'course' => $course,
'enabletracking' => $enabletracking
]
);
if ($role) {
$user = $this->getDataGenerator()->create_and_enrol($course, $role);
$this->setUser($user);
}
// Check the access information.
$result = get_h5pactivity_access_information::execute($activity->id);
$result = external_api::clean_returnvalue(get_h5pactivity_access_information::execute_returns(), $result);
$this->assertCount(0, $result['warnings']);
unset($result['warnings']);
// Check the values for capabilities.
foreach ($result as $capname => $capvalue) {
if (in_array($capname, $enabledcaps)) {
$this->assertTrue($capvalue);
} else {
$this->assertFalse($capvalue);
}
}
}
/**
* Data provider for get_h5pactivity_access_information.
*
* @return array
*/
public function get_h5pactivity_access_information_data(): array {
return [
'Admin, tracking enabled' => [
'', 1, ['canview', 'canreviewattempts', 'canaddinstance']
],
'Admin, tracking disabled' => [
'', 0, ['canview', 'canreviewattempts', 'canaddinstance']
],
'Student, tracking enabled' => [
'student', 1, ['canview', 'cansubmit']
],
'Student, tracking disabled' => [
'student', 0, ['canview']
],
'Teacher, tracking enabled' => [
'editingteacher', 1, [
'canview',
'canreviewattempts',
'canaddinstance'
]
],
'Teacher, tracking disabled' => [
'editingteacher', 0, [
'canview',
'canreviewattempts',
'canaddinstance'
]
],
];
}
/**
* Test dml_missing_record_exception in get_h5pactivity_access_information.
*/
public function test_dml_missing_record_exception(): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
// Call the WS using an unexisting h5pactivityid.
$this->expectException(dml_missing_record_exception::class);
$result = get_h5pactivity_access_information::execute(1);
}
}
+428
View File
@@ -0,0 +1,428 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* External function test for get_results.
*
* @package mod_h5pactivity
* @category external
* @since Moodle 3.9
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_h5pactivity\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
use mod_h5pactivity\local\manager;
use core_external\external_api;
use externallib_advanced_testcase;
use dml_missing_record_exception;
/**
* External function test for get_results.
*
* @package mod_h5pactivity
* @copyright 2020 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class get_results_test extends externallib_advanced_testcase {
/**
* Test the behaviour of get_results.
*
* @dataProvider execute_data
* @param int $enabletracking the activity tracking enable
* @param int $reviewmode the activity review mode
* @param string $loginuser the user which calls the webservice
* @param string|null $participant the user to get the data
* @param bool $createattempts if the student user has attempts created
* @param int|null $count the expected number of attempts returned (null for exception)
*/
public function test_execute(int $enabletracking, int $reviewmode, string $loginuser,
?string $participant, bool $createattempts, ?int $count): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$activity = $this->getDataGenerator()->create_module('h5pactivity',
['course' => $course, 'enabletracking' => $enabletracking, 'reviewmode' => $reviewmode]);
$manager = manager::create_from_instance($activity);
$cm = $manager->get_coursemodule();
// Prepare users: 1 teacher, 1 student and 1 unenroled user.
$users = [
'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'),
'student' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
'other' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
];
$attempts = [];
$generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
if ($createattempts) {
$user = $users['student'];
$params = ['cmid' => $cm->id, 'userid' => $user->id];
$attempts['student'] = $generator->create_content($activity, $params);
}
// Create another 2 attempts for the user "other" to validate no cross attempts are returned.
$user = $users['other'];
$params = ['cmid' => $cm->id, 'userid' => $user->id];
$attempts['other'] = $generator->create_content($activity, $params);
// Execute external method.
$this->setUser($users[$loginuser]);
$attemptid = $attempts[$participant]->id ?? 0;
$result = get_results::execute($activity->id, [$attemptid]);
$result = external_api::clean_returnvalue(
get_results::execute_returns(),
$result
);
// Validate general structure.
$this->assertArrayHasKey('activityid', $result);
$this->assertArrayHasKey('attempts', $result);
$this->assertArrayHasKey('warnings', $result);
$this->assertEquals($activity->id, $result['activityid']);
if ($count === null) {
$this->assertCount(1, $result['warnings']);
$this->assertCount(0, $result['attempts']);
return;
}
$this->assertCount(0, $result['warnings']);
$this->assertCount(1, $result['attempts']);
// Validate attempt.
$attempt = $result['attempts'][0];
$this->assertEquals($attemptid, $attempt['id']);
// Validate results.
$this->assertArrayHasKey('results', $attempt);
$this->assertCount($count, $attempt['results']);
foreach ($attempt['results'] as $value) {
$this->assertEquals($attemptid, $value['attemptid']);
$this->assertArrayHasKey('subcontent', $value);
$this->assertArrayHasKey('rawscore', $value);
$this->assertArrayHasKey('maxscore', $value);
$this->assertArrayHasKey('duration', $value);
$this->assertArrayHasKey('track', $value);
if (isset($value['options'])) {
foreach ($value['options'] as $option) {
$this->assertArrayHasKey('description', $option);
$this->assertArrayHasKey('id', $option);
}
}
}
}
/**
* Data provider for the test_execute tests.
*
* @return array
*/
public function execute_data(): array {
return [
'Teacher reviewing an attempt' => [
1, manager::REVIEWCOMPLETION, 'editingteacher', 'student', true, 1
],
'Teacher try to review an inexistent attempt' => [
1, manager::REVIEWCOMPLETION, 'editingteacher', 'student', false, null
],
'Teacher reviewing attempt with student review mode off' => [
1, manager::REVIEWNONE, 'editingteacher', 'student', true, 1
],
'Student reviewing own attempt' => [
1, manager::REVIEWCOMPLETION, 'student', 'student', true, 1
],
'Student reviewing an inexistent attempt' => [
1, manager::REVIEWCOMPLETION, 'student', 'student', false, null
],
'Student reviewing own attempt with review mode off' => [
1, manager::REVIEWNONE, 'student', 'student', true, null
],
'Student try to stalk other student attempt' => [
1, manager::REVIEWCOMPLETION, 'student', 'other', false, null
],
'Teacher trying to review an attempt without tracking enabled' => [
0, manager::REVIEWNONE, 'editingteacher', 'student', true, null
],
'Student trying to review an attempt without tracking enabled' => [
0, manager::REVIEWNONE, 'editingteacher', 'student', true, null
],
'Student trying to stalk another student attempt without tracking enabled' => [
0, manager::REVIEWNONE, 'editingteacher', 'student', true, null
],
];
}
/**
* Test the behaviour of get_results.
*
* @dataProvider execute_multipleattempts_data
* @param string $loginuser the user which calls the webservice
* @param array $getattempts the attempts to get the data
* @param array $warnings warnigns expected
* @param array $reports data expected
*
*/
public function test_execute_multipleattempts(string $loginuser,
array $getattempts, array $warnings, array $reports): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);
$manager = manager::create_from_instance($activity);
$cm = $manager->get_coursemodule();
// Prepare users: 1 teacher, 2 student.
$users = [
'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'),
'student1' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
'student2' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
];
$attempts = [];
// Generate attempts for student 1 and 2.
$generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
$user = $users['student1'];
$params = ['cmid' => $cm->id, 'userid' => $user->id];
$attempts['student1_1'] = $generator->create_content($activity, $params);
$attempts['student1_2'] = $generator->create_content($activity, $params);
$user = $users['student2'];
$params = ['cmid' => $cm->id, 'userid' => $user->id];
$attempts['student2_1'] = $generator->create_content($activity, $params);
$attempts['student2_2'] = $generator->create_content($activity, $params);
// Execute external method.
$this->setUser($users[$loginuser]);
$attemptids = [];
foreach ($getattempts as $getattempt) {
$attemptids[] = $attempts[$getattempt]->id ?? 0;
}
$result = get_results::execute($activity->id, $attemptids);
$result = external_api::clean_returnvalue(
get_results::execute_returns(),
$result
);
// Validate general structure.
$this->assertArrayHasKey('activityid', $result);
$this->assertArrayHasKey('attempts', $result);
$this->assertArrayHasKey('warnings', $result);
$this->assertEquals($activity->id, $result['activityid']);
$this->assertCount(count($warnings), $result['warnings']);
$this->assertCount(count($reports), $result['attempts']);
// Validate warnings.
$expectedwarnings = [];
foreach ($warnings as $warningattempt) {
$id = $attempts[$warningattempt]->id ?? 0;
$expectedwarnings[$id] = $warningattempt;
}
foreach ($result['warnings'] as $warning) {
$this->assertEquals('h5pactivity_attempts', $warning['item']);
$this->assertEquals(1, $warning['warningcode']);
$this->assertArrayHasKey($warning['itemid'], $expectedwarnings);
}
// Validate attempts.
$expectedattempts = [];
foreach ($reports as $expectedattempt) {
$id = $attempts[$expectedattempt]->id;
$expectedattempts[$id] = $expectedattempt;
}
foreach ($result['attempts'] as $value) {
$this->assertArrayHasKey($value['id'], $expectedattempts);
}
}
/**
* Data provider for the test_execute_multipleattempts tests.
*
* @return array
*/
public function execute_multipleattempts_data(): array {
return [
// Teacher cases.
'Teacher reviewing students attempts' => [
'editingteacher', ['student1_1', 'student2_1'], [], ['student1_1', 'student2_1']
],
'Teacher reviewing invalid attempt' => [
'editingteacher', ['student1_1', 'invalid'], ['invalid'], ['student1_1']
],
'Teacher reviewing empty attempts list' => [
'editingteacher', [], [], []
],
// Student cases.
'Student reviewing own students attempts' => [
'student1', ['student1_1', 'student1_2'], [], ['student1_1', 'student1_2']
],
'Student reviewing invalid attempt' => [
'student1', ['student1_1', 'invalid'], ['invalid'], ['student1_1']
],
'Student reviewing trying to access another user attempts' => [
'student1', ['student1_1', 'student2_1'], ['student2_1'], ['student1_1']
],
'Student reviewing empty attempts list' => [
'student1', [], [], ['student1_1', 'student1_2']
],
];
}
/**
* Test the behaviour of get_results using mixed activityid.
*
* @dataProvider execute_mixactivities_data
* @param string $activityname the activity name to use
* @param string $attemptname the attempt name to use
* @param string $expectedwarnings expected warning attempt
* @param string $expectedattempt expected result attempt
*
*/
public function test_execute_mixactivities(string $activityname, string $attemptname,
string $expectedwarnings, string $expectedattempt): void {
$this->resetAfterTest();
$this->setAdminUser();
// Create 2 courses.
$course1 = $this->getDataGenerator()->create_course();
$course2 = $this->getDataGenerator()->create_course();
// Prepare users: 1 teacher, 1 student.
$user = $this->getDataGenerator()->create_and_enrol($course1, 'student');
$this->getDataGenerator()->enrol_user($user->id, $course2->id, 'student');
// Create our base activity.
$activity11 = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course1]);
$manager11 = manager::create_from_instance($activity11);
$cm11 = $manager11->get_coursemodule();
// Create a second activity in the same course to check if the retuned attempt is the correct one.
$activity12 = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course1]);
$manager12 = manager::create_from_instance($activity12);
$cm12 = $manager12->get_coursemodule();
// Create a second activity on a different course.
$activity21 = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course2]);
$manager21 = manager::create_from_instance($activity21);
$cm21 = $manager21->get_coursemodule();
$activities = [
'11' => $activity11->id,
'12' => $activity12->id,
'21' => $activity21->id,
'inexistent' => 0,
];
// Generate attempts.
$generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
$params = ['cmid' => $cm11->id, 'userid' => $user->id];
$attempt11 = $generator->create_content($activity11, $params);
$params = ['cmid' => $cm12->id, 'userid' => $user->id];
$attempt12 = $generator->create_content($activity12, $params);
$params = ['cmid' => $cm21->id, 'userid' => $user->id];
$attempt21 = $generator->create_content($activity21, $params);
$attempts = [
'11' => $attempt11->id,
'12' => $attempt12->id,
'21' => $attempt21->id,
'inexistent' => 0,
];
if ($activityname == 'inexistent') {
$this->expectException(dml_missing_record_exception::class);
}
// Execute external method.
$this->setUser($user);
$attemptid = $attempts[$attemptname];
$result = get_results::execute($activities[$activityname], [$attemptid]);
$result = external_api::clean_returnvalue(
get_results::execute_returns(),
$result
);
// Validate general structure.
$this->assertArrayHasKey('activityid', $result);
$this->assertArrayHasKey('attempts', $result);
$this->assertArrayHasKey('warnings', $result);
if (empty($expectedwarnings)) {
$this->assertEmpty($result['warnings']);
} else {
$this->assertEquals('h5pactivity_attempts', $result['warnings'][0]['item']);
$this->assertEquals(1, $result['warnings'][0]['warningcode']);
$this->assertEquals($attempts[$expectedwarnings], $result['warnings'][0]['itemid']);
}
if (empty($expectedattempt)) {
$this->assertEmpty($result['attempts']);
} else {
$this->assertEquals($attempts[$expectedattempt], $result['attempts'][0]['id']);
}
}
/**
* Data provider for the test_execute_multipleattempts tests.
*
* @return array
*/
public function execute_mixactivities_data(): array {
return [
// Teacher cases.
'Correct activity id' => [
'11', '11', '', '11'
],
'Wrong activity id' => [
'21', '11', '11', ''
],
'Inexistent activity id' => [
'inexistent', '11', '', ''
],
'Inexistent attempt id' => [
'11', 'inexistent', 'inexistent', ''
],
];
}
}
@@ -0,0 +1,249 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* External function test for get_user_attempts.
*
* @package mod_h5pactivity
* @category external
* @since Moodle 3.11
* @copyright 2020 Ilya Tregubov <ilya@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_h5pactivity\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
use mod_h5pactivity\local\manager;
use core_external\external_api;
use externallib_advanced_testcase;
/**
* External function test for get_user_attempts.
*
* @package mod_h5pactivity
* @copyright 2020 Ilya Tregubov <ilya@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class get_user_attempts_test extends externallib_advanced_testcase {
/**
* Test the behaviour of get_user_attempts getting more than one user at once.
*
* @dataProvider execute_multipleusers_data
* @param string $loginuser the user which calls the webservice
* @param string[] $participants the users to get the data
* @param string[] $warnings the expected users with warnings
* @param string[] $resultusers expected users in the resultusers
*/
public function test_execute_multipleusers(string $loginuser, array $participants,
array $warnings, array $resultusers): void {
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$activity = $this->getDataGenerator()->create_module('h5pactivity',
['course' => $course]);
$manager = manager::create_from_instance($activity);
$cm = $manager->get_coursemodule();
$users = ['editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher')];
// Prepare users.
foreach ($participants as $participant) {
if ($participant == 'noenrolled') {
$users[$participant] = $this->getDataGenerator()->create_user();
} else {
$users[$participant] = $this->getDataGenerator()->create_and_enrol($course, 'student');
}
}
// Generate attempts (student1 with 1 attempt, student2 with 2 etc).
$generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
$attemptcount = 1;
foreach ($users as $key => $user) {
if (($key == 'noattempts') || ($key == 'noenrolled') || ($key == 'editingteacher')) {
$countattempts[$user->id] = 0;
} else {
$params = ['cmid' => $cm->id, 'userid' => $user->id];
for ($i = 1; $i <= $attemptcount; $i++) {
$generator->create_content($activity, $params);
}
$countattempts[$user->id] = $attemptcount;
$attemptcount++;
}
}
// Execute external method.
$this->setUser($users[$loginuser]);
if ($loginuser == 'student1') {
$this->expectException('moodle_exception');
$this->expectExceptionMessage('h5pactivity:reviewattempts required view attempts' .
' of all enrolled users');
}
$result = get_user_attempts::execute($activity->id);
$result = external_api::clean_returnvalue(
get_user_attempts::execute_returns(),
$result
);
$this->assertCount(count($warnings), $result['warnings']);
// Teacher is excluded.
$this->assertCount(count($resultusers), $result['usersattempts']);
$expectedwarnings = [];
foreach ($warnings as $warninguser) {
$id = $users[$warninguser]->id;
$expectedwarnings[$id] = $warninguser;
}
foreach ($result['warnings'] as $warning) {
$this->assertEquals('user', $warning['item']);
$this->assertEquals(1, $warning['warningcode']);
$this->assertArrayHasKey($warning['itemid'], $expectedwarnings);
}
$expectedusers = [];
foreach ($resultusers as $resultuser) {
$id = $users[$resultuser]->id;
$expectedusers[$id] = $resultuser;
}
foreach ($result['usersattempts'] as $usersattempts) {
$this->assertArrayHasKey('userid', $usersattempts);
$userid = $usersattempts['userid'];
$this->assertArrayHasKey($userid, $expectedusers);
$this->assertCount($countattempts[$userid], $usersattempts['attempts']);
if ($countattempts[$userid]) {
$this->assertArrayHasKey('scored', $usersattempts);
}
}
}
/**
* Data provider for the test_execute_multipleusers.
*
* @return array
*/
public function execute_multipleusers_data(): array {
return [
// Teacher checks.
'Teacher checking students with attempts' => [
'editingteacher',
['student1', 'student2', 'student3', 'student4', 'student5'],
[],
['student1', 'student2', 'student3', 'student4', 'student5'],
],
'Teacher checking 2 students with atempts and one not' => [
'editingteacher',
['student1', 'student2', 'noattempts'],
[],
['student1', 'student2', 'noattempts'],
],
'Teacher checking no students' => [
'editingteacher',
[],
[],
[],
],
'Teacher checking one student and a no enrolled user' => [
'editingteacher',
['student1', 'noenrolled'],
[],
['student1'],
],
// Permission check.
'Student checking attempts and another user' => [
'student1',
['student1', 'student2'],
['student2'],
['student1'],
],
];
}
/**
* Data provider for {@see test_execute_with_sortorder}
*
* @return array[]
*/
public function execute_with_sortorder(): array {
return [
'Sort by id' => ['id', ['user01', 'user02']],
'Sort by id desc' => ['id desc', ['user02', 'user01']],
'Sort by id asc' => ['id asc', ['user01', 'user02']],
'Sort by firstname' => ['firstname', ['user01', 'user02']],
'Sort by firstname desc' => ['firstname desc', ['user02', 'user01']],
'Sort by firstname asc' => ['firstname asc', ['user01', 'user02']],
'Sort by lastname' => ['lastname', ['user02', 'user01']],
'Sort by lastname desc' => ['lastname desc', ['user01', 'user02']],
'Sort by lastname asc' => ['lastname asc', ['user02', 'user01']],
// Edge cases (should fall back to default).
'Sort by empty string' => ['', ['user01', 'user02']],
'Sort by invalid field' => ['invalid', ['user01', 'user02']],
];
}
/**
* Test external execute method with sortorder
*
* @param string $sortorder
* @param string[] $expectedorder
*
* @dataProvider execute_with_sortorder
*/
public function test_execute_with_sortorder(string $sortorder, array $expectedorder): void {
$this->resetAfterTest();
$this->setAdminUser();
// Create course, module.
$course = $this->getDataGenerator()->create_course();
$module = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);
// Couple of enrolled users in the course.
$users['user01'] = $this->getDataGenerator()->create_and_enrol($course, 'student', [
'username' => 'user01',
'firstname' => 'Adam',
'lastname' => 'Zebra',
]);
$users['user02'] = $this->getDataGenerator()->create_and_enrol($course, 'student', [
'username' => 'user02',
'firstname' => 'Zoe',
'lastname' => 'Apples',
]);
$result = external_api::clean_returnvalue(
get_user_attempts::execute_returns(),
get_user_attempts::execute($module->id, $sortorder)
);
// Map expected order of usernames to user IDs.
$expectedorderbyuserid = array_map(static function(string $username) use ($users): int {
return $users[$username]->id;
}, $expectedorder);
// The order should match the ordering of user attempt user IDs.
$this->assertEquals($expectedorderbyuserid, array_column($result['usersattempts'], 'userid'));
}
}
@@ -0,0 +1,117 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_h5pactivity\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
use mod_h5pactivity\local\manager;
use core_external\external_api;
use externallib_advanced_testcase;
/**
* External function test for log_report_viewed.
*
* @package mod_h5pactivity
* @category external
* @covers \mod_h5pactivity\external\log_report_viewed
* @since Moodle 3.11
* @copyright 2021 Ilya Tregubov <ilya@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class log_report_viewed_test extends externallib_advanced_testcase {
/**
* Test the behaviour of log_report_viewed.
*
* @dataProvider execute_data
* @param int $enabletracking the activity tracking enable
* @param int $reviewmode the activity review mode
* @param string $loginuser the user which calls the webservice
* @param string|null $participant the user to log the data
*/
public function test_execute(int $enabletracking, int $reviewmode, string $loginuser, ?string $participant): void {
$this->resetAfterTest();
$this->setAdminUser();
// Create a course.
$course = $this->getDataGenerator()->create_course();
// Enrol users: 1 teacher, 1 student.
$users = [
'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'),
'student' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
];
// Add h5p activity.
$activity = $this->getDataGenerator()->create_module('h5pactivity',
['course' => $course, 'enabletracking' => $enabletracking, 'reviewmode' => $reviewmode]);
// Create attempt for h5p activity.
$attempts = [];
$generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
$user = $users['student'];
$manager = manager::create_from_instance($activity);
$cm = $manager->get_coursemodule();
$params = ['cmid' => $cm->id, 'userid' => $user->id];
$attempts['student'] = $generator->create_content($activity, $params);
// Redirect events to the sink, so we can recover them later.
$sink = $this->redirectEvents();
// Execute external method.
$this->setUser($users[$loginuser]);
$attemptid = $attempts[$participant]->id ?? 0;
$result = log_report_viewed::execute($activity->id, $user->id, $attemptid);
$result = external_api::clean_returnvalue(
log_report_viewed::execute_returns(),
$result
);
// Validate general structure.
$this->assertArrayHasKey('status', $result);
$events = $sink->get_events();
$event = end($events);
// Check the event details are correct.
$this->assertInstanceOf('mod_h5pactivity\event\report_viewed', $event);
$this->assertEquals(\context_module::instance($cm->id), $event->get_context());
$this->assertEquals($cm->instance, $event->other['instanceid']);
$this->assertEquals($user->id, $event->other['userid']);
$this->assertEquals($attemptid, $event->other['attemptid']);
}
/**
* Data provider for the test_execute tests.
*
* @return array
*/
public static function execute_data(): array {
return [
'Student reviewing own attempt' => [
1, manager::REVIEWCOMPLETION, 'student', 'student'
],
'Teacher reviewing student attempts' => [
1, manager::REVIEWCOMPLETION, 'editingteacher', 'student'
],
];
}
}
+155
View File
@@ -0,0 +1,155 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* External function test for view_h5pactivity.
*
* @package mod_h5pactivity
* @category external
* @since Moodle 3.9
* @copyright 2020 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_h5pactivity\external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
use core_external\external_api;
use externallib_advanced_testcase;
use stdClass;
use context_module;
use course_modinfo;
/**
* External function test for view_h5pactivity.
*
* @package mod_h5pactivity
* @copyright 2020 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class view_h5pactivity_test extends externallib_advanced_testcase {
/**
* Test test_view_h5pactivity invalid id.
*/
public function test_view_h5pactivity_invalid_id(): void {
$this->resetAfterTest();
$this->setAdminUser();
$this->expectException('moodle_exception');
$result = view_h5pactivity::execute(0);
}
/**
* Test test_view_h5pactivity user not enrolled.
*/
public function test_view_h5pactivity_user_not_enrolled(): void {
$this->resetAfterTest();
$this->setAdminUser();
// Setup scenario.
$scenario = $this->setup_scenario();
// Test not-enrolled user.
$usernotenrolled = self::getDataGenerator()->create_user();
$this->setUser($usernotenrolled);
$this->expectException('moodle_exception');
$result = view_h5pactivity::execute($scenario->h5pactivity->id);
}
/**
* Test test_view_h5pactivity user student.
*/
public function test_view_h5pactivity_user_student(): void {
$this->resetAfterTest();
$this->setAdminUser();
// Setup scenario.
$scenario = $this->setup_scenario();
$cm = get_coursemodule_from_instance('h5pactivity', $scenario->h5pactivity->id);
$this->setUser($scenario->student);
// Trigger and capture the event.
$sink = $this->redirectEvents();
$result = view_h5pactivity::execute($scenario->h5pactivity->id);
$result = external_api::clean_returnvalue(view_h5pactivity::execute_returns(), $result);
$this->assertTrue($result['status']);
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = array_shift($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_h5pactivity\event\course_module_viewed', $event);
$this->assertEquals($scenario->contextmodule, $event->get_context());
$h5pactivity = new \moodle_url('/mod/h5pactivity/view.php', array('id' => $cm->id));
$this->assertEquals($h5pactivity, $event->get_url());
$this->assertEventContextNotUsed($event);
$this->assertNotEmpty($event->get_name());
}
/**
* Test test_view_h5pactivity user missing capabilities.
*/
public function test_view_h5pactivity_user_missing_capabilities(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Setup scenario.
$scenario = $this->setup_scenario();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
// Test user with no capabilities.
// We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
assign_capability('mod/h5pactivity:view', CAP_PROHIBIT, $studentrole->id, $scenario->contextmodule->id);
// Empty all the caches that may be affected by this change.
accesslib_clear_all_caches_for_unit_testing();
course_modinfo::clear_instance_cache();
$this->setUser($scenario->student);
$this->expectException('moodle_exception');
$result = view_h5pactivity::execute($scenario->h5pactivity->id);
}
/**
* Create a scenario to use into the tests.
*
* @return stdClass $scenario
*/
protected function setup_scenario() {
$course = $this->getDataGenerator()->create_course();
$h5pactivity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
$contextmodule = context_module::instance($h5pactivity->cmid);
$scenario = new stdClass();
$scenario->contextmodule = $contextmodule;
$scenario->student = $student;
$scenario->h5pactivity = $h5pactivity;
return $scenario;
}
}