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
@@ -0,0 +1,45 @@
<?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_resource\backup;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . "/phpunit/classes/restore_date_testcase.php");
/**
* Restore date tests.
*
* @package mod_resource
* @copyright 2017 onwards Ankit Agarwal <ankit.agrr@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class restore_date_test extends \restore_date_testcase {
public function test_restore_dates(): void {
global $DB;
$time = 10000;
list($course, $resource) = $this->create_course_and_module('resource');
// Do backup and restore.
$newcourseid = $this->backup_and_restore($course);
$newresource = $DB->get_record('resource', ['course' => $newcourseid]);
$this->assertFieldsNotRolledForward($resource, $newresource, ['timemodified']);
}
}
@@ -0,0 +1,90 @@
@mod @mod_resource
Feature: Teacher can specify different display options for the resource
In order to provide more information about a file
As a teacher
I need to be able to show size, type and modified date
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following "activities" exist:
| activity | course | name | intro | defaultfilename | uploaded |
| resource | C1 | Myfile | My cool file | mod/resource/tests/fixtures/samplefile.txt | 1 |
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
Scenario: Specifying no additional display options for a file resource
When I am on the "Myfile" "resource activity editing" page
And I set the following fields to these values:
| Show upload/modified date | 0 |
| showsize | 0 |
| showtype | 0 |
And I press "Save and display"
Then ".resourcedetails" "css_element" should not exist
And I am on "Course 1" course homepage
And ".activity.resource .resourcelinkdetails" "css_element" should not exist
Scenario Outline: Specifying different display options for a file resource
When I am on the "Myfile" "resource activity editing" page
And I set the following fields to these values:
| display | 5 |
| Show size | <showsize> |
| Show type | <showtype> |
| Show upload/modified date | <showdate> |
And I press "Save and display"
Then I <seesize> see "6 bytes" in the ".resourcedetails" "css_element"
And I <seetype> see "TXT" in the ".resourcedetails" "css_element"
And I <seedate> see "Uploaded" in the ".resourcedetails" "css_element"
And I am on "Course 1" course homepage
And I <seesize> see "6 bytes" in the ".activity.resource .resourcelinkdetails" "css_element"
And I <seetype> see "TXT" in the ".activity.resource .activitybadge" "css_element"
And I <seedate> see "Uploaded" in the ".activity.resource .resourcelinkdetails" "css_element"
Examples:
| showsize | showtype | showdate | seesize | seetype | seedate |
| 1 | 0 | 0 | should | should not | should not |
| 0 | 0 | 1 | should not | should not | should |
| 1 | 1 | 0 | should | should | should not |
| 1 | 0 | 1 | should | should not | should |
| 0 | 1 | 1 | should not | should | should |
| 1 | 1 | 1 | should | should | should |
Scenario Outline: Specify different display options for an embedded file resource
When I am on the "Myfile" "resource activity editing" page
And I set the following fields to these values:
| display | Embed |
| Show type | <showtype> |
| Display resource description | <showdesc> |
And I press "Save and display"
Then I <seetype> see "TXT" in the "region-main" "region"
And I <seedesc> see "My cool file" in the "region-main" "region"
Examples:
| showtype | showdesc | seetype | seedesc |
| 1 | 0 | should | should not |
| 1 | 1 | should | should |
| 0 | 1 | should not | should |
| 0 | 0 | should not | should not |
Scenario: Specifying only show type for a file resource
When I am on the "Myfile" "resource activity editing" page
And I set the following fields to these values:
| display | 5 |
| Show size | 0 |
| Show type | 1 |
| Show upload/modified date | 0 |
And I press "Save and display"
Then I should see "TXT" in the ".resourcedetails" "css_element"
Then I should not see "6 bytes" in the ".resourcedetails" "css_element"
And I should see "TXT" in the ".resourcedetails" "css_element"
And I should not see "Uploaded" in the ".resourcedetails" "css_element"
And I am on "Course 1" course homepage
And I should see "TXT" in the ".activity.resource .activitybadge" "css_element"
And ".activity.resource .resourcelinkdetails" "css_element" should not exist
@@ -0,0 +1,89 @@
@mod @mod_resource @core_completion @_file_upload
Feature: View activity completion information for file resources
In order to have visibility of file resource completion requirements
As a student
I need to be able to view my file resource completion progress
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Vinnie | Student1 | student1@example.com |
| teacher1 | Darrell | Teacher1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | category | enablecompletion |
| Course 1 | C1 | 0 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| teacher1 | C1 | editingteacher |
And the following config values are set as admin:
| displayoptions | 0,1,2,3,4,5,6 | resource |
@javascript
Scenario Outline: The manual completion button will be shown on the course page for Open, In pop-up, New window and Force download display mode if Show activity completion conditions is set to No
Given the following "activities" exist:
| activity | course | name | display | showsize | showtype | showdate | completion | defaultfilename | popupwidth | popupheight | uploaded |
| resource | C1 | Myfile | <display> | 0 | 0 | 0 | 1 | mod/resource/tests/fixtures/samplefile.txt | 620 | 450 | 1 |
And I am on the "Course 1" course page logged in as teacher1
# Teacher view.
And "Myfile" should have the "Mark as done" completion condition
# Student view.
When I am on the "Course 1" course page logged in as student1
Then the manual completion button for "Myfile" should exist
And the manual completion button of "Myfile" is displayed as "Mark as done"
And I toggle the manual completion state of "Myfile"
And the manual completion button of "Myfile" is displayed as "Done"
Examples:
| display |
| 5 |
| 6 |
| 4 |
| 3 |
@javascript
Scenario: The manual completion button will be shown on the activity page and course page if Show activity completion conditions is set to Yes
Given the following "activities" exist:
| activity | course | name | display | defaultfilename | uploaded |
| resource | C1 | Myfile | 1 | mod/resource/tests/fixtures/samplefile.txt | 1 |
And I am on the "Course 1" "course editing" page logged in as "teacher1"
And I expand all fieldsets
And I set the field "Show activity completion conditions" to "Yes"
And I press "Save and display"
And I am on the "Myfile" "resource activity editing" page
And I set the following fields to these values:
| Students must manually mark the activity as done | 1 |
And I click on "Save and return to course" "button"
# Teacher view.
And "Myfile" should have the "Mark as done" completion condition
And I am on the "Myfile" "resource activity" page
And the manual completion button for "Myfile" should exist
And the manual completion button for "Myfile" should be disabled
# Student view.
When I am on the "Course 1" course page logged in as student1
Then the manual completion button for "Myfile" should exist
And I am on the "Myfile" "resource activity" page
And the manual completion button of "Myfile" is displayed as "Mark as done"
And I toggle the manual completion state of "Myfile"
And the manual completion button of "Myfile" is displayed as "Done"
@javascript
Scenario: View automatic completion items
Given the following "activities" exist:
| activity | course | name | display | defaultfilename | uploaded |
| resource | C1 | Myfile | 1 | mod/resource/tests/fixtures/samplefile.txt | 1 |
And I am on the "Course 1" "course editing" page logged in as "teacher1"
And I expand all fieldsets
And I set the field "Show activity completion conditions" to "Yes"
And I press "Save and display"
And I am on the "Myfile" "resource activity editing" page
And I set the following fields to these values:
| Add requirements | 1 |
| View the activity | 1 |
And I press "Save and display"
# Teacher view.
And I am on the "Myfile" "resource activity" page
And "Myfile" should have the "View" completion condition
# Student view.
When I am on the "Myfile" "resource activity" page logged in as student1
Then the "View" completion condition of "Myfile" is displayed as "done"
+101
View File
@@ -0,0 +1,101 @@
<?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/>.
/**
* Events test.
*
* @package mod_resource
* @copyright 2014 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_resource\event;
/**
* Resource events test cases.
*
* @package mod_resource
* @copyright 2014 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class events_test extends \advanced_testcase {
/**
* Setup is called before calling test case.
*/
public function setUp(): void {
$this->resetAfterTest();
// Must be a non-guest user to create resources.
$this->setAdminUser();
}
/**
* Test course_module_instance_list_viewed event.
*/
public function test_course_module_instance_list_viewed(): void {
// There is no proper API to call to trigger this event, so what we are
// doing here is simply making sure that the events returns the right information.
$course = $this->getDataGenerator()->create_course();
$params = array(
'context' => \context_course::instance($course->id)
);
$event = \mod_resource\event\course_module_instance_list_viewed::create($params);
// Triggering and capturing the event.
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = reset($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_resource\event\course_module_instance_list_viewed', $event);
$this->assertEquals(\context_course::instance($course->id), $event->get_context());
$this->assertEventContextNotUsed($event);
}
/**
* Test course_module_viewed event.
*/
public function test_course_module_viewed(): void {
// There is no proper API to call to trigger this event, so what we are
// doing here is simply making sure that the events returns the right information.
$course = $this->getDataGenerator()->create_course();
$resource = $this->getDataGenerator()->create_module('resource', array('course' => $course->id));
$params = array(
'context' => \context_module::instance($resource->cmid),
'objectid' => $resource->id
);
$event = \mod_resource\event\course_module_viewed::create($params);
// Triggering and capturing the event.
$sink = $this->redirectEvents();
$event->trigger();
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = reset($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_resource\event\course_module_viewed', $event);
$this->assertEquals(\context_module::instance($resource->cmid), $event->get_context());
$this->assertEquals($resource->id, $event->objectid);
$this->assertEventContextNotUsed($event);
}
}
+254
View File
@@ -0,0 +1,254 @@
<?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_resource;
use core_external\external_api;
use externallib_advanced_testcase;
use mod_resource_external;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
/**
* External mod_resource functions unit tests
*
* @package mod_resource
* @category external
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.0
*/
class externallib_test extends externallib_advanced_testcase {
/**
* Test view_resource
*/
public function test_view_resource(): void {
global $DB;
$this->resetAfterTest(true);
$this->setAdminUser();
// Setup test data.
$course = $this->getDataGenerator()->create_course();
$resource = $this->getDataGenerator()->create_module('resource', array('course' => $course->id));
$context = \context_module::instance($resource->cmid);
$cm = get_coursemodule_from_instance('resource', $resource->id);
// Test invalid instance id.
try {
mod_resource_external::view_resource(0);
$this->fail('Exception expected due to invalid mod_resource instance id.');
} catch (\moodle_exception $e) {
$this->assertEquals('invalidrecord', $e->errorcode);
}
// Test not-enrolled user.
$user = self::getDataGenerator()->create_user();
$this->setUser($user);
try {
mod_resource_external::view_resource($resource->id);
$this->fail('Exception expected due to not enrolled user.');
} catch (\moodle_exception $e) {
$this->assertEquals('requireloginerror', $e->errorcode);
}
// Test user with full capabilities.
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
// Trigger and capture the event.
$sink = $this->redirectEvents();
$result = mod_resource_external::view_resource($resource->id);
$result = external_api::clean_returnvalue(mod_resource_external::view_resource_returns(), $result);
$events = $sink->get_events();
$this->assertCount(1, $events);
$event = array_shift($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_resource\event\course_module_viewed', $event);
$this->assertEquals($context, $event->get_context());
$moodleurl = new \moodle_url('/mod/resource/view.php', array('id' => $cm->id));
$this->assertEquals($moodleurl, $event->get_url());
$this->assertEventContextNotUsed($event);
$this->assertNotEmpty($event->get_name());
// 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/resource:view', CAP_PROHIBIT, $studentrole->id, $context->id);
// Empty all the caches that may be affected by this change.
accesslib_clear_all_caches_for_unit_testing();
\course_modinfo::clear_instance_cache();
try {
mod_resource_external::view_resource($resource->id);
$this->fail('Exception expected due to missing capability.');
} catch (\moodle_exception $e) {
$this->assertEquals('requireloginerror', $e->errorcode);
}
}
/**
* Test test_mod_resource_get_resources_by_courses
*/
public function test_mod_resource_get_resources_by_courses(): void {
global $DB;
$this->resetAfterTest(true);
$course1 = self::getDataGenerator()->create_course();
$course2 = self::getDataGenerator()->create_course();
$student = self::getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id);
self::setUser($student);
// First resource.
$record = new \stdClass();
$record->course = $course1->id;
$resource1 = self::getDataGenerator()->create_module('resource', $record);
// Second resource.
$record = new \stdClass();
$record->course = $course2->id;
$resource2 = self::getDataGenerator()->create_module('resource', $record);
// Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
$enrol = enrol_get_plugin('manual');
$enrolinstances = enrol_get_instances($course2->id, true);
foreach ($enrolinstances as $courseenrolinstance) {
if ($courseenrolinstance->enrol == "manual") {
$instance2 = $courseenrolinstance;
break;
}
}
$enrol->enrol_user($instance2, $student->id, $studentrole->id);
$returndescription = mod_resource_external::get_resources_by_courses_returns();
// Create what we expect to be returned when querying the two courses.
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'lang',
'contentfiles', 'tobemigrated', 'legacyfiles', 'legacyfileslast', 'display', 'displayoptions',
'filterfiles', 'revision', 'timemodified', 'section', 'visible', 'groupmode', 'groupingid');
// Add expected coursemodule and data.
$resource1->coursemodule = $resource1->cmid;
$resource1->introformat = 1;
$resource1->contentformat = 1;
$resource1->section = 0;
$resource1->visible = true;
$resource1->groupmode = 0;
$resource1->groupingid = 0;
$resource1->introfiles = [];
$resource1->contentfiles = [];
$resource1->lang = '';
$resource2->coursemodule = $resource2->cmid;
$resource2->introformat = 1;
$resource2->contentformat = 1;
$resource2->section = 0;
$resource2->visible = true;
$resource2->groupmode = 0;
$resource2->groupingid = 0;
$resource2->introfiles = [];
$resource2->contentfiles = [];
$resource2->lang = '';
foreach ($expectedfields as $field) {
$expected1[$field] = $resource1->{$field};
$expected2[$field] = $resource2->{$field};
}
$expectedresources = array($expected2, $expected1);
// Call the external function passing course ids.
$result = mod_resource_external::get_resources_by_courses(array($course2->id, $course1->id));
$result = external_api::clean_returnvalue($returndescription, $result);
// Remove the contentfiles (to be checked bellow).
$result['resources'][0]['contentfiles'] = [];
$result['resources'][1]['contentfiles'] = [];
// Now, check that we retrieve the same data we created.
$this->assertEquals($expectedresources, $result['resources']);
$this->assertCount(0, $result['warnings']);
// Call the external function without passing course id.
$result = mod_resource_external::get_resources_by_courses();
$result = external_api::clean_returnvalue($returndescription, $result);
// Remove the contentfiles (to be checked bellow).
$result['resources'][0]['contentfiles'] = [];
$result['resources'][1]['contentfiles'] = [];
// Check that without course ids we still get the correct data.
$this->assertEquals($expectedresources, $result['resources']);
$this->assertCount(0, $result['warnings']);
// Add a file to the intro.
$fileintroname = "fileintro.txt";
$filerecordinline = array(
'contextid' => \context_module::instance($resource2->cmid)->id,
'component' => 'mod_resource',
'filearea' => 'intro',
'itemid' => 0,
'filepath' => '/',
'filename' => $fileintroname,
);
$fs = get_file_storage();
$timepost = time();
$fs->create_file_from_string($filerecordinline, 'image contents (not really)');
$result = mod_resource_external::get_resources_by_courses(array($course2->id, $course1->id));
$result = external_api::clean_returnvalue($returndescription, $result);
// Check that we receive correctly the files.
$this->assertCount(1, $result['resources'][0]['introfiles']);
$this->assertEquals($fileintroname, $result['resources'][0]['introfiles'][0]['filename']);
$this->assertCount(1, $result['resources'][0]['contentfiles']);
$this->assertCount(1, $result['resources'][1]['contentfiles']);
// Test autogenerated resource.
$this->assertEquals('resource2.txt', $result['resources'][0]['contentfiles'][0]['filename']);
$this->assertEquals('resource1.txt', $result['resources'][1]['contentfiles'][0]['filename']);
// Unenrol user from second course.
$enrol->unenrol_user($instance2, $student->id);
array_shift($expectedresources);
// Call the external function without passing course id.
$result = mod_resource_external::get_resources_by_courses();
$result = external_api::clean_returnvalue($returndescription, $result);
// Remove the contentfiles (to be checked bellow).
$result['resources'][0]['contentfiles'] = [];
$this->assertEquals($expectedresources, $result['resources']);
// Call for the second course we unenrolled the user from, expected warning.
$result = mod_resource_external::get_resources_by_courses(array($course2->id));
$this->assertCount(1, $result['warnings']);
$this->assertEquals('1', $result['warnings'][0]['warningcode']);
$this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
}
}
+1
View File
@@ -0,0 +1 @@
Hello!
+112
View File
@@ -0,0 +1,112 @@
<?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/>.
/**
* Data generator.
*
* @package mod_resource
* @copyright 2013 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Resource module data generator class.
*
* @package mod_resource
* @copyright 2013 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_resource_generator extends testing_module_generator {
/**
* Creates new resource module instance. By default it contains a short
* text file.
*
* @param array|stdClass $record data for module being generated. Requires 'course' key
* (an id or the full object). Also can have any fields from add module form, and a
* 'defaultfilename' to set the name of the file created if no draft ID is supplied.
* @param null|array $options general options for course module. Since 2.6 it is
* possible to omit this argument by merging options into $record
* @return stdClass record from module-defined table with additional field
* cmid (corresponding id in course_modules table)
*/
public function create_instance($record = null, array $options = null) {
global $CFG, $USER;
require_once($CFG->dirroot . '/lib/resourcelib.php');
// Ensure the record can be modified without affecting calling code.
$record = (object)(array)$record;
// Fill in optional values if not specified.
if (!isset($record->display)) {
$record->display = RESOURCELIB_DISPLAY_AUTO;
}
if (!isset($record->printintro)) {
$record->printintro = 0;
}
if (!isset($record->showsize)) {
$record->showsize = 0;
}
if (!isset($record->showtype)) {
$record->showtype = 0;
}
if (!isset($record->uploaded)) {
$record->uploaded = 0;
}
// The 'files' value corresponds to the draft file area ID. If not
// specified, create a default file.
if (!isset($record->files)) {
if (empty($USER->username) || $USER->username === 'guest') {
throw new coding_exception('resource generator requires a current user');
}
$usercontext = context_user::instance($USER->id);
$filename = $record->defaultfilename ?? 'resource' . ($this->instancecount + 1) . '.txt';
// Pick a random context id for specified user.
$record->files = file_get_unused_draft_itemid();
// Add actual file there.
$filerecord = ['component' => 'user', 'filearea' => 'draft',
'contextid' => $usercontext->id, 'itemid' => $record->files,
'filename' => basename($filename), 'filepath' => '/'];
$fs = get_file_storage();
if ($record->uploaded == 1) {
// For uploading a file, it's required to specify a file, how not!
if (!isset($record->defaultfilename)) {
throw new coding_exception(
'The $record->defaultfilename option is required in order to upload a file');
}
// We require the full file path to exist when uploading a real file (fixture or whatever).
$fullfilepath = $CFG->dirroot . '/' . $record->defaultfilename;
if (!is_readable($fullfilepath)) {
throw new coding_exception(
'The $record->defaultfilename option must point to an existing file within dirroot');
}
// Create file using pathname (defaultfilename) set.
$fs->create_file_from_pathname($filerecord, $fullfilepath);
} else {
// If defaultfilename is not set, create file from string "resource 1.txt".
$fs->create_file_from_string($filerecord, 'Test resource ' . $filename . ' file');
}
}
// Do work to actually add the instance.
return parent::create_instance($record, $options);
}
}
+123
View File
@@ -0,0 +1,123 @@
<?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_resource;
/**
* PHPUnit data generator testcase.
*
* @package mod_resource
* @category phpunit
* @covers \mod_resource_generator
* @copyright 2013 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class generator_test extends \advanced_testcase {
public function test_generator(): void {
global $DB, $SITE;
$this->resetAfterTest(true);
// Must be a non-guest user to create resources.
$this->setAdminUser();
// There are 0 resources initially.
$this->assertEquals(0, $DB->count_records('resource'));
// Create the generator object and do standard checks.
$generator = $this->getDataGenerator()->get_plugin_generator('mod_resource');
$this->assertInstanceOf('mod_resource_generator', $generator);
$this->assertEquals('resource', $generator->get_modulename());
// Create three instances in the site course.
$generator->create_instance(array('course' => $SITE->id));
$generator->create_instance(array('course' => $SITE->id));
$resource = $generator->create_instance(array('course' => $SITE->id));
$this->assertEquals(3, $DB->count_records('resource'));
// Check the course-module is correct.
$cm = get_coursemodule_from_instance('resource', $resource->id);
$this->assertEquals($resource->id, $cm->instance);
$this->assertEquals('resource', $cm->modname);
$this->assertEquals($SITE->id, $cm->course);
// Check the context is correct.
$context = \context_module::instance($cm->id);
$this->assertEquals($resource->cmid, $context->instanceid);
// Check that generated resource module contains a file.
$fs = get_file_storage();
$files = $fs->get_area_files($context->id, 'mod_resource', 'content', false, '', false);
$file = array_values($files)[0];
$this->assertCount(1, $files);
$this->assertEquals('resource3.txt', $file->get_filename());
$this->assertEquals('Test resource resource3.txt file', $file->get_content());
// Create a new resource specifying the file name.
$resource = $generator->create_instance(['course' => $SITE->id, 'defaultfilename' => 'myfile.pdf']);
// Check that generated resource module contains a file with the specified name.
$cm = get_coursemodule_from_instance('resource', $resource->id);
$context = \context_module::instance($cm->id);
$files = $fs->get_area_files($context->id, 'mod_resource', 'content', false, '', false);
$file = array_values($files)[0];
$this->assertCount(1, $files);
$this->assertEquals('myfile.pdf', $file->get_filename());
$this->assertEquals('Test resource myfile.pdf file', $file->get_content());
// Create a new resource uploading a file.
$resource = $generator->create_instance([
'course' => $SITE->id,
'uploaded' => true,
'defaultfilename' => 'mod/resource/tests/fixtures/samplefile.txt',
]);
// Check that generated resource module contains the uploaded samplefile.txt.
$cm = get_coursemodule_from_instance('resource', $resource->id);
$context = \context_module::instance($cm->id);
$files = $fs->get_area_files($context->id, 'mod_resource', 'content', false, '', false);
$file = array_values($files)[0];
$this->assertCount(1, $files);
$this->assertEquals('samplefile.txt', $file->get_filename());
$this->assertEquals('Hello!', $file->get_content());
// Try to generate a resource with uploaded file without specifying the file.
try {
$resource = $generator->create_instance([
'course' => $SITE->id,
'uploaded' => true,
]);
$this->assertTrue(false, 'coding_exception expected, defaultfilename is required');
} catch (\Exception $e) {
$this->assertInstanceOf(\coding_exception::class, $e);
$this->assertStringContainsString('defaultfilename option is required', $e->getMessage());
}
// Try to generate a resource with uploaded file pointing to non-existing file.
try {
$resource = $generator->create_instance([
'course' => $SITE->id,
'uploaded' => true,
'defaultfilename' => 'mod/resource/tests/fixtures/doesnotexist.txt',
]);
$this->assertTrue(false, 'coding_exception expected, defaultfilename must point to an existing file');
} catch (\Exception $e) {
$this->assertInstanceOf(\coding_exception::class, $e);
$this->assertStringContainsString('defaultfilename option must point to an existing file', $e->getMessage());
}
}
}
+285
View File
@@ -0,0 +1,285 @@
<?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/>.
/**
* Unit tests for mod_resource lib
*
* @package mod_resource
* @category external
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.0
*/
namespace mod_resource;
defined('MOODLE_INTERNAL') || die();
/**
* Unit tests for mod_resource lib
*
* @package mod_resource
* @category external
* @copyright 2015 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.0
*/
class lib_test extends \advanced_testcase {
/**
* Prepares things before this test case is initialised
* @return void
*/
public static function setUpBeforeClass(): void {
global $CFG;
require_once($CFG->dirroot . '/mod/resource/lib.php');
}
/**
* Test resource_view
* @return void
*/
public function test_resource_view(): void {
global $CFG;
$CFG->enablecompletion = 1;
$this->resetAfterTest();
$this->setAdminUser();
// Setup test data.
$course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
$resource = $this->getDataGenerator()->create_module('resource', array('course' => $course->id),
array('completion' => 2, 'completionview' => 1));
$context = \context_module::instance($resource->cmid);
$cm = get_coursemodule_from_instance('resource', $resource->id);
// Trigger and capture the event.
$sink = $this->redirectEvents();
resource_view($resource, $course, $cm, $context);
$events = $sink->get_events();
// 2 additional events thanks to completion.
$this->assertCount(3, $events);
$event = array_shift($events);
// Checking that the event contains the expected values.
$this->assertInstanceOf('\mod_resource\event\course_module_viewed', $event);
$this->assertEquals($context, $event->get_context());
$moodleurl = new \moodle_url('/mod/resource/view.php', array('id' => $cm->id));
$this->assertEquals($moodleurl, $event->get_url());
$this->assertEventContextNotUsed($event);
$this->assertNotEmpty($event->get_name());
// Check completion status.
$completion = new \completion_info($course);
$completiondata = $completion->get_data($cm);
$this->assertEquals(1, $completiondata->completionstate);
}
/**
* Tests the resource_get_coursemodule_info function.
*
* Note: This currently doesn't test every aspect of the function, mainly focusing on the icon.
*/
public function test_get_coursemodule_info(): void {
global $DB, $USER;
$this->resetAfterTest();
$this->setAdminUser();
// Create course.
$generator = $this->getDataGenerator();
$course = $generator->create_course();
// Create a resource with no files.
$draftid = file_get_unused_draft_itemid();
$resource1 = $generator->create_module('resource', array('course' => $course->id,
'name' => 'R1', 'files' => $draftid));
// Create a resource with one file.
$draftid = file_get_unused_draft_itemid();
$contextid = \context_user::instance($USER->id)->id;
$filerecord = array('component' => 'user', 'filearea' => 'draft', 'contextid' => $contextid,
'itemid' => $draftid, 'filename' => 'r2.txt', 'filepath' => '/');
$fs = get_file_storage();
$fs->create_file_from_string($filerecord, 'Test');
$resource2 = $generator->create_module('resource', array('course' => $course->id,
'name' => 'R2', 'files' => $draftid));
// Create a resource with two files.
$draftid = file_get_unused_draft_itemid();
$filerecord = array('component' => 'user', 'filearea' => 'draft', 'contextid' => $contextid,
'itemid' => $draftid, 'filename' => 'r3.txt', 'filepath' => '/', 'sortorder' => 1);
$fs->create_file_from_string($filerecord, 'Test');
$filerecord['filename'] = 'r3.doc';
$filerecord['sortorder'] = 2;
$fs->create_file_from_string($filerecord, 'Test');
$resource3 = $generator->create_module('resource', array('course' => $course->id,
'name' => 'R3', 'files' => $draftid));
// Try get_coursemodule_info for first one.
$info = resource_get_coursemodule_info(
$DB->get_record('course_modules', array('id' => $resource1->cmid)));
// The name should be set. There is no overridden icon.
$this->assertEquals('R1', $info->name);
$this->assertEmpty($info->icon);
// For second one, there should be an overridden icon.
$info = resource_get_coursemodule_info(
$DB->get_record('course_modules', array('id' => $resource2->cmid)));
$this->assertEquals('R2', $info->name);
$this->assertEquals('f/text', $info->icon);
// For third one, it should use the highest sortorder icon.
$info = resource_get_coursemodule_info(
$DB->get_record('course_modules', array('id' => $resource3->cmid)));
$this->assertEquals('R3', $info->name);
$this->assertEquals('f/document', $info->icon);
}
public function test_resource_core_calendar_provide_event_action(): void {
$this->resetAfterTest();
$this->setAdminUser();
// Create the activity.
$course = $this->getDataGenerator()->create_course();
$resource = $this->getDataGenerator()->create_module('resource', array('course' => $course->id));
// Create a calendar event.
$event = $this->create_action_event($course->id, $resource->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_resource_core_calendar_provide_event_action($event, $factory);
// Confirm the event was decorated.
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
$this->assertEquals(get_string('view'), $actionevent->get_name());
$this->assertInstanceOf('moodle_url', $actionevent->get_url());
$this->assertEquals(1, $actionevent->get_item_count());
$this->assertTrue($actionevent->is_actionable());
}
public function test_resource_core_calendar_provide_event_action_already_completed(): void {
global $CFG;
$this->resetAfterTest();
$this->setAdminUser();
$CFG->enablecompletion = 1;
// Create the activity.
$course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
$resource = $this->getDataGenerator()->create_module('resource', array('course' => $course->id),
array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
// Get some additional data.
$cm = get_coursemodule_from_instance('resource', $resource->id);
// Create a calendar event.
$event = $this->create_action_event($course->id, $resource->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Mark the activity as completed.
$completion = new \completion_info($course);
$completion->set_module_viewed($cm);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_resource_core_calendar_provide_event_action($event, $factory);
// Ensure result was null.
$this->assertNull($actionevent);
}
/**
* Test mod_resource_core_calendar_provide_event_action with user override
*/
public function test_resource_core_calendar_provide_event_action_user_override(): void {
global $CFG, $USER;
$this->resetAfterTest();
$this->setAdminUser();
$user = $this->getDataGenerator()->create_user();
$CFG->enablecompletion = 1;
// Create the activity.
$course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
$resource = $this->getDataGenerator()->create_module('resource', array('course' => $course->id),
array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
// Get some additional data.
$cm = get_coursemodule_from_instance('resource', $resource->id);
// Create a calendar event.
$event = $this->create_action_event($course->id, $resource->id,
\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
// Mark the activity as completed.
$completion = new \completion_info($course);
$completion->set_module_viewed($cm);
// Create an action factory.
$factory = new \core_calendar\action_factory();
// Decorate action event.
$actionevent = mod_resource_core_calendar_provide_event_action($event, $factory, $USER->id);
// Decorate action with a userid override.
$actionevent2 = mod_resource_core_calendar_provide_event_action($event, $factory, $user->id);
// Ensure result was null because it has been marked as completed for the associated user.
// Logic was brought across from the "_already_completed" function.
$this->assertNull($actionevent);
// Confirm the event was decorated.
$this->assertNotNull($actionevent2);
$this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent2);
$this->assertEquals(get_string('view'), $actionevent2->get_name());
$this->assertInstanceOf('moodle_url', $actionevent2->get_url());
$this->assertEquals(1, $actionevent2->get_item_count());
$this->assertTrue($actionevent2->is_actionable());
}
/**
* Creates an action event.
*
* @param int $courseid The course id.
* @param int $instanceid The instance id.
* @param string $eventtype The event type.
* @return bool|calendar_event
*/
private function create_action_event($courseid, $instanceid, $eventtype) {
$event = new \stdClass();
$event->name = 'Calendar event';
$event->modulename = 'resource';
$event->courseid = $courseid;
$event->instance = $instanceid;
$event->type = CALENDAR_EVENT_TYPE_ACTION;
$event->eventtype = $eventtype;
$event->timestart = time();
return \calendar_event::create($event);
}
}
+123
View File
@@ -0,0 +1,123 @@
<?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/>.
/**
* Resource search unit tests.
*
* @package mod_resource
* @category test
* @copyright 2016 Eric Merrill {@link http://www.merrilldigital.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_resource\search;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/search/tests/fixtures/testable_core_search.php');
/**
* Provides the unit tests for forum search.
*
* @package mod_resource
* @category test
* @copyright 2016 Eric Merrill {@link http://www.merrilldigital.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class search_test extends \advanced_testcase {
/**
* @var string Area id
*/
protected $resourceareaid = null;
public function setUp(): void {
$this->resetAfterTest(true);
set_config('enableglobalsearch', true);
$this->resourceareaid = \core_search\manager::generate_areaid('mod_resource', 'activity');
// Set \core_search::instance to the mock_search_engine as we don't require the search engine to be working to test this.
$search = \testable_core_search::instance();
}
/**
* Test for resource file attachments.
*
* @return void
*/
public function test_attach_files(): void {
global $USER;
$this->setAdminUser();
// Setup test data.
$course = $this->getDataGenerator()->create_course();
$fs = get_file_storage();
$usercontext = \context_user::instance($USER->id);
$record = new \stdClass();
$record->course = $course->id;
$record->files = file_get_unused_draft_itemid();
// Attach the main file. We put them in the draft area, create_module will move them.
$filerecord = array(
'contextid' => $usercontext->id,
'component' => 'user',
'filearea' => 'draft',
'itemid' => $record->files,
'filepath' => '/',
'filename' => 'mainfile',
'sortorder' => 1
);
$fs->create_file_from_string($filerecord, 'Test resource file');
// Attach a second file.
$filerecord['filename'] = 'extrafile';
$filerecord['sortorder'] = 0;
$fs->create_file_from_string($filerecord, 'Test resource file 2');
$resource = $this->getDataGenerator()->create_module('resource', $record);
$searcharea = \core_search\manager::get_search_area($this->resourceareaid);
$this->assertInstanceOf('\mod_resource\search\activity', $searcharea);
$recordset = $searcharea->get_recordset_by_timestamp(0);
$nrecords = 0;
foreach ($recordset as $record) {
$doc = $searcharea->get_document($record);
$searcharea->attach_files($doc);
$files = $doc->get_files();
// Resources should return all added files.
$this->assertCount(2, $files);
$filenames = array();
foreach ($files as $file) {
$filenames[] = $file->get_filename();
}
$this->assertContains('mainfile', $filenames);
$this->assertContains('extrafile', $filenames);
$nrecords++;
}
$recordset->close();
$this->assertEquals(1, $nrecords);
}
}