MDL-74608 activities: a new option to force the activity language
For a long time, Moodle has had the feature to force the language for a whole course. This change adds the same feature at activity level. The course-level feature was controlled by a capability moodle/course:setforcedlanguage, and I decided to use the same capability to control this feature. I think a new capability would be overkill.
This commit is contained in:
@@ -341,7 +341,7 @@ class backup_module_structure_step extends backup_structure_step {
|
||||
'visibleold', 'groupmode', 'groupingid',
|
||||
'completion', 'completiongradeitemnumber', 'completionpassgrade',
|
||||
'completionview', 'completionexpected',
|
||||
'availability', 'showdescription', 'downloadcontent'));
|
||||
'availability', 'showdescription', 'downloadcontent', 'lang'));
|
||||
|
||||
$tags = new backup_nested_element('tags');
|
||||
$tag = new backup_nested_element('tag', array('id'), array('name', 'rawname'));
|
||||
|
||||
@@ -4491,6 +4491,10 @@ class restore_module_structure_step extends restore_structure_step {
|
||||
$data->availability = upgrade_group_members_only($data->groupingid, $data->availability);
|
||||
}
|
||||
|
||||
if (!has_capability('moodle/course:setforcedlanguage', context_course::instance($data->course))) {
|
||||
unset($data->lang);
|
||||
}
|
||||
|
||||
// course_module record ready, insert it
|
||||
$newitemid = $DB->insert_record('course_modules', $data);
|
||||
// save mapping
|
||||
|
||||
@@ -57,6 +57,7 @@ abstract class helper_for_get_mods_by_courses {
|
||||
$moddetails['coursemodule'] = $modinstance->coursemodule;
|
||||
$moddetails['course'] = $modinstance->course;
|
||||
$moddetails['name'] = $modinstance->name;
|
||||
$moddetails['lang'] = clean_param($modinstance->lang, PARAM_LANG);
|
||||
if (!$capabilityforintro || has_capability($capabilityforintro, $context)) {
|
||||
$moddetails['intro'] = $modinstance->intro;
|
||||
$moddetails['introformat'] = $modinstance->introformat;
|
||||
@@ -130,6 +131,7 @@ abstract class helper_for_get_mods_by_courses {
|
||||
'visible' => new external_value(PARAM_BOOL, 'Visible', VALUE_OPTIONAL),
|
||||
'groupmode' => new external_value(PARAM_INT, 'Group mode', VALUE_OPTIONAL),
|
||||
'groupingid' => new external_value(PARAM_INT, 'Group id', VALUE_OPTIONAL),
|
||||
'lang' => new external_value(PARAM_SAFEDIR, 'Forced activity language', VALUE_OPTIONAL),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,11 +251,12 @@ class course_edit_form extends moodleform {
|
||||
$mform->addElement('select', 'theme', get_string('forcetheme'), $themes);
|
||||
}
|
||||
|
||||
$languages=array();
|
||||
$languages[''] = get_string('forceno');
|
||||
$languages += get_string_manager()->get_list_of_translations();
|
||||
if ((empty($course->id) && guess_if_creator_will_have_course_capability('moodle/course:setforcedlanguage', $categorycontext))
|
||||
|| (!empty($course->id) && has_capability('moodle/course:setforcedlanguage', $coursecontext))) {
|
||||
|
||||
$languages = ['' => get_string('forceno')];
|
||||
$languages += get_string_manager()->get_list_of_translations();
|
||||
|
||||
$mform->addElement('select', 'lang', get_string('forcelanguage'), $languages);
|
||||
$mform->setDefault('lang', $courseconfig->lang);
|
||||
}
|
||||
|
||||
+13
-2
@@ -70,6 +70,11 @@ function add_moduleinfo($moduleinfo, $course, $mform = null) {
|
||||
if (isset($moduleinfo->downloadcontent)) {
|
||||
$newcm->downloadcontent = $moduleinfo->downloadcontent;
|
||||
}
|
||||
if (has_capability('moodle/course:setforcedlanguage', context_course::instance($course->id))) {
|
||||
$newcm->lang = $moduleinfo->lang ?? null;
|
||||
} else {
|
||||
$newcm->lang = null;
|
||||
}
|
||||
$newcm->groupmode = $moduleinfo->groupmode;
|
||||
$newcm->groupingid = $moduleinfo->groupingid;
|
||||
$completion = new completion_info($course);
|
||||
@@ -552,6 +557,13 @@ function update_moduleinfo($cm, $moduleinfo, $course, $mform = null) {
|
||||
$moduleinfo->course = $course->id;
|
||||
$moduleinfo = set_moduleinfo_defaults($moduleinfo);
|
||||
|
||||
$modcontext = context_module::instance($moduleinfo->coursemodule);
|
||||
if (has_capability('moodle/course:setforcedlanguage', $modcontext)) {
|
||||
$cm->lang = $moduleinfo->lang ?? null;
|
||||
} else {
|
||||
unset($cm->lang);
|
||||
}
|
||||
|
||||
if (!empty($course->groupmodeforce) or !isset($moduleinfo->groupmode)) {
|
||||
$moduleinfo->groupmode = $cm->groupmode; // Keep original.
|
||||
}
|
||||
@@ -611,8 +623,6 @@ function update_moduleinfo($cm, $moduleinfo, $course, $mform = null) {
|
||||
|
||||
$DB->update_record('course_modules', $cm);
|
||||
|
||||
$modcontext = context_module::instance($moduleinfo->coursemodule);
|
||||
|
||||
// Update embedded links and save files.
|
||||
if (plugin_supports('mod', $moduleinfo->modulename, FEATURE_MOD_INTRO, true)) {
|
||||
$moduleinfo->intro = file_save_draft_area_files($moduleinfo->introeditor['itemid'], $modcontext->id,
|
||||
@@ -745,6 +755,7 @@ function get_moduleinfo_data($cm, $course) {
|
||||
$data->completiongradeitemnumber = $cm->completiongradeitemnumber;
|
||||
$data->showdescription = $cm->showdescription;
|
||||
$data->downloadcontent = $cm->downloadcontent;
|
||||
$data->lang = $cm->lang;
|
||||
$data->tags = core_tag_tag::get_item_tags_array('core', 'course_modules', $cm->id);
|
||||
if (!empty($CFG->enableavailability)) {
|
||||
$data->availabilityconditionsjson = $cm->availability;
|
||||
|
||||
@@ -625,11 +625,8 @@ abstract class moodleform_mod extends moodleform {
|
||||
$mform->addElement('modvisible', 'visible', get_string($modvisiblelabel), null,
|
||||
array('allowstealth' => $allowstealth, 'sectionvisible' => $section->visible, 'cm' => $this->_cm));
|
||||
$mform->addHelpButton('visible', $modvisiblelabel);
|
||||
if (!empty($this->_cm)) {
|
||||
$context = context_module::instance($this->_cm->id);
|
||||
if (!has_capability('moodle/course:activityvisibility', $context)) {
|
||||
$mform->hardFreeze('visible');
|
||||
}
|
||||
if (!empty($this->_cm) && !has_capability('moodle/course:activityvisibility', $this->get_context())) {
|
||||
$mform->hardFreeze('visible');
|
||||
}
|
||||
|
||||
if ($this->_features->idnumber) {
|
||||
@@ -638,6 +635,13 @@ abstract class moodleform_mod extends moodleform {
|
||||
$mform->addHelpButton('cmidnumber', 'idnumbermod');
|
||||
}
|
||||
|
||||
if (has_capability('moodle/course:setforcedlanguage', $this->get_context())) {
|
||||
$languages = ['' => get_string('forceno')];
|
||||
$languages += get_string_manager()->get_list_of_translations();
|
||||
|
||||
$mform->addElement('select', 'lang', get_string('forcelanguage'), $languages);
|
||||
}
|
||||
|
||||
if ($CFG->downloadcoursecontentallowed) {
|
||||
$choices = [
|
||||
DOWNLOAD_COURSE_CONTENT_DISABLED => get_string('no'),
|
||||
@@ -900,9 +904,8 @@ abstract class moodleform_mod extends moodleform {
|
||||
|
||||
$rolenamestring = null;
|
||||
if ($isupdate) {
|
||||
$context = context_module::instance($this->_cm->id);
|
||||
$capabilities = ['moodle/rating:rate', "mod/{$this->_cm->modname}:rate"];
|
||||
$rolenames = get_role_names_with_caps_in_context($context, $capabilities);
|
||||
$rolenames = get_role_names_with_caps_in_context($this->get_context(), $capabilities);
|
||||
$rolenamestring = implode(', ', $rolenames);
|
||||
} else {
|
||||
$rolenamestring = get_string('capabilitychecknotavailable', 'rating');
|
||||
|
||||
@@ -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/>.
|
||||
|
||||
namespace core_course;
|
||||
use backup;
|
||||
|
||||
/**
|
||||
* Restore date tests.
|
||||
*
|
||||
* @package core_course
|
||||
* @copyright 2022 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \backup_module_structure_step
|
||||
* @covers \restore_module_structure_step
|
||||
*/
|
||||
class backup_restore_activity_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test that duplicating a page preserves the lang setting.
|
||||
*/
|
||||
public function test_duplicating_page_preserves_lang() {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// Make a test course.
|
||||
$generator = $this->getDataGenerator();
|
||||
$course = $generator->create_course();
|
||||
|
||||
// Create a page with forced language set.
|
||||
$page = $generator->create_module('page', ['course' => $course->id, 'lang' => 'en']);
|
||||
|
||||
// Duplicate the page.
|
||||
$newpagecm = duplicate_module($course, get_fast_modinfo($course)->get_cm($page->cmid));
|
||||
|
||||
// Verify the settings of the duplicated activity.
|
||||
$this->assertEquals('en', $newpagecm->lang);
|
||||
}
|
||||
|
||||
public function test_activity_forced_lang_not_restored_without_capability() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
// Make a test course.
|
||||
$generator = $this->getDataGenerator();
|
||||
$course = $generator->create_course();
|
||||
|
||||
// Create a page with forced language set.
|
||||
$generator->create_module('page', ['course' => $course->id, 'lang' => 'en']);
|
||||
|
||||
// Backup the course.
|
||||
$backupid = $this->backup_course($course);
|
||||
|
||||
// Create a manger user without 'moodle/course:setforcedlanguage' to do the restore.
|
||||
$manager = $generator->create_user();
|
||||
$generator->role_assign('manager', $manager->id);
|
||||
role_change_permission($DB->get_field('role', 'id', ['shortname' => 'manager'], MUST_EXIST),
|
||||
\context_system::instance(), 'moodle/course:setforcedlanguage', CAP_INHERIT);
|
||||
$this->setUser($manager);
|
||||
|
||||
// Restore the course.
|
||||
$newcourseid = $this->restore_course($backupid);
|
||||
|
||||
// Verify the settings of the duplicated activity.
|
||||
$newmodinfo = get_fast_modinfo($newcourseid);
|
||||
$newcms = $newmodinfo->instances['page'];
|
||||
$newpagecm = reset($newcms);
|
||||
$this->assertNull($newpagecm->lang);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a backup of the course.
|
||||
*
|
||||
* @param \stdClass $course The course object.
|
||||
* @return string Unique identifier for this backup.
|
||||
*/
|
||||
protected function backup_course(\stdClass $course): string {
|
||||
global $CFG, $USER;
|
||||
|
||||
// Turn off file logging, otherwise it can't delete the file (Windows).
|
||||
$CFG->backup_file_logger_level = backup::LOG_NONE;
|
||||
|
||||
// Do backup with default settings. MODE_IMPORT means it will just
|
||||
// create the directory and not zip it.
|
||||
$bc = new \backup_controller(backup::TYPE_1COURSE, $course->id,
|
||||
backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_IMPORT,
|
||||
$USER->id);
|
||||
$backupid = $bc->get_backupid();
|
||||
$bc->execute_plan();
|
||||
$bc->destroy();
|
||||
|
||||
return $backupid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores a backup that has been made earlier.
|
||||
*
|
||||
* @param string $backupid The unique identifier of the backup.
|
||||
* @return int The new course id.
|
||||
*/
|
||||
protected function restore_course(string $backupid): int {
|
||||
global $CFG, $DB, $USER;
|
||||
|
||||
// Turn off file logging, otherwise it can't delete the file (Windows).
|
||||
$CFG->backup_file_logger_level = backup::LOG_NONE;
|
||||
|
||||
$defaultcategoryid = $DB->get_field('course_categories', 'id',
|
||||
['parent' => 0], IGNORE_MULTIPLE);
|
||||
|
||||
// Do restore to new course with default settings.
|
||||
$newcourseid = \restore_dbops::create_new_course('Restored course', 'R1', $defaultcategoryid);
|
||||
$rc = new \restore_controller($backupid, $newcourseid,
|
||||
backup::INTERACTIVE_NO, backup::MODE_GENERAL, $USER->id,
|
||||
backup::TARGET_NEW_COURSE);
|
||||
|
||||
$precheck = $rc->execute_precheck();
|
||||
$this->assertTrue($precheck);
|
||||
|
||||
$rc->execute_plan();
|
||||
$rc->destroy();
|
||||
|
||||
return $newcourseid;
|
||||
}
|
||||
}
|
||||
@@ -5,36 +5,30 @@ Feature: Add activities to courses
|
||||
I need to add activites to a course
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| student2 | Student | 2 | student2@example.com |
|
||||
And the following "courses" exist:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course 1 | Course 1 | topics |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | Course 1 | student |
|
||||
| student2 | Course 1 | student |
|
||||
| Course 1 | Course 1 | topics |
|
||||
|
||||
@javascript
|
||||
Scenario: Add an activity to a course
|
||||
Given I am on the "Course 1" Course page logged in as admin
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
When I add a "Database" to section "3" and I fill the form with:
|
||||
| Name | Test name |
|
||||
| Description | Test database description |
|
||||
| ID number | TESTNAME |
|
||||
| Allow comments on entries | Yes |
|
||||
| Name | Test name |
|
||||
| Description | Test database description |
|
||||
| ID number | TESTNAME |
|
||||
| Allow comments on entries | Yes |
|
||||
| Force language | English |
|
||||
And I turn editing mode off
|
||||
Then I should not see "Adding a new"
|
||||
And I turn editing mode on
|
||||
And I open "Test name" actions menu
|
||||
And I click on "Edit settings" "link" in the "Test name" activity
|
||||
And I expand all fieldsets
|
||||
And the field "Name" matches value "Test name"
|
||||
And the field "ID number" matches value "TESTNAME"
|
||||
And the field "Allow comments on entries" matches value "Yes"
|
||||
And the following fields match these values:
|
||||
| Name | Test name |
|
||||
| ID number | TESTNAME |
|
||||
| Allow comments on entries | Yes |
|
||||
| Force language | English (en) |
|
||||
|
||||
@javascript
|
||||
Scenario: Add an activity supplying only the name
|
||||
|
||||
@@ -120,6 +120,7 @@ class modlib_test extends \advanced_testcase {
|
||||
$expecteddata->showdescription = $assigncm->showdescription;
|
||||
$expecteddata->downloadcontent = $assigncm->downloadcontent;
|
||||
$expecteddata->tags = \core_tag_tag::get_item_tags_array('core', 'course_modules', $assigncm->id);
|
||||
$expecteddata->lang = null;
|
||||
$expecteddata->availabilityconditionsjson = null;
|
||||
$expecteddata->advancedgradingmethod_submissions = null;
|
||||
if ($items = \grade_item::fetch_all(array('itemtype' => 'mod', 'itemmodule' => 'assign',
|
||||
|
||||
+1
-1
@@ -178,7 +178,7 @@ $string['course:configuredownloadcontent'] = 'Configure download course content'
|
||||
$string['course:downloadcoursecontent'] = 'Download course content';
|
||||
$string['course:enrolconfig'] = 'Configure enrol instances in courses';
|
||||
$string['course:enrolreview'] = 'Review course enrolments';
|
||||
$string['course:setforcedlanguage'] = 'Force course language';
|
||||
$string['course:setforcedlanguage'] = 'Force course or activity language';
|
||||
$string['course:ignoreavailabilityrestrictions'] = 'Ignore availability restrictions';
|
||||
$string['course:ignorefilesizelimits'] = 'Use files larger than any file size restrictions';
|
||||
$string['course:isincompletionreports'] = 'Be shown on completion reports';
|
||||
|
||||
@@ -526,7 +526,7 @@ class core_string_manager_standard implements core_string_manager {
|
||||
$cachekey = 'list_'.$this->get_key_suffix();
|
||||
$cachedlist = $this->menucache->get($cachekey);
|
||||
if ($cachedlist !== false) {
|
||||
// The cache content is invalid.
|
||||
// The cache content is valid.
|
||||
if ($returnall or empty($this->translist)) {
|
||||
return $cachedlist;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1352,7 +1352,7 @@ function get_coursemodules_in_course($modulename, $courseid, $extrafields='') {
|
||||
* in the course. Returns an empty array on any errors.
|
||||
*
|
||||
* The returned objects includle the columns cw.section, cm.visible,
|
||||
* cm.groupmode, and cm.groupingid, and are indexed by cm.id.
|
||||
* cm.groupmode, cm.groupingid and cm.lang and are indexed by cm.id.
|
||||
*
|
||||
* @global object
|
||||
* @global object
|
||||
@@ -1380,7 +1380,7 @@ function get_all_instances_in_courses($modulename, $courses, $userid=NULL, $incl
|
||||
$params['modulename'] = $modulename;
|
||||
|
||||
if (!$rawmods = $DB->get_records_sql("SELECT cm.id AS coursemodule, m.*, cw.section, cm.visible AS visible,
|
||||
cm.groupmode, cm.groupingid
|
||||
cm.groupmode, cm.groupingid, cm.lang
|
||||
FROM {course_modules} cm, {course_sections} cw, {modules} md,
|
||||
{".$modulename."} m
|
||||
WHERE cm.course $coursessql AND
|
||||
|
||||
@@ -1094,6 +1094,7 @@ $capabilities = array(
|
||||
'clonepermissionsfrom' => 'moodle/course:update'
|
||||
),
|
||||
|
||||
// Ability to set a forced language for a course or activity.
|
||||
'moodle/course:setforcedlanguage' => array(
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
|
||||
+2
-1
@@ -93,7 +93,7 @@
|
||||
<FIELD NAME="groupmode" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="groupmodeforce" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="defaultgroupingid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="default grouping used in course modules, does not have key intentionally"/>
|
||||
<FIELD NAME="lang" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="lang" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false" COMMENT="Forced language for this course. Null or '' means 'Do not force'. Otherwise a Moodle lang pack name like 'fr' or 'en_us'."/>
|
||||
<FIELD NAME="calendartype" TYPE="char" LENGTH="30" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="theme" TYPE="char" LENGTH="50" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
@@ -309,6 +309,7 @@
|
||||
<FIELD NAME="availability" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Availability restrictions for viewing this activity, in JSON format. Null if no restrictions."/>
|
||||
<FIELD NAME="deletioninprogress" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="downloadcontent" TYPE="int" LENGTH="1" NOTNULL="false" DEFAULT="1" SEQUENCE="false" COMMENT="Whether the ability to download course module content is enabled for this activity"/>
|
||||
<FIELD NAME="lang" TYPE="char" LENGTH="30" NOTNULL="false" SEQUENCE="false" COMMENT="Forced language for this activity. Null or '' means 'Do not force'. Otherwise a Moodle lang pack name like 'fr' or 'en_us'."/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
|
||||
@@ -2879,5 +2879,20 @@ privatefiles,moodle|/user/files.php';
|
||||
upgrade_main_savepoint(true, 2022061500.00);
|
||||
}
|
||||
|
||||
if ($oldversion < 2022081200.01) {
|
||||
|
||||
// Define field lang to be added to course_modules.
|
||||
$table = new xmldb_table('course_modules');
|
||||
$field = new xmldb_field('lang', XMLDB_TYPE_CHAR, '30', null, null, null, null, 'downloadcontent');
|
||||
|
||||
// Conditionally launch add field lang.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2022081200.01);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+13
-4
@@ -865,6 +865,7 @@ class course_modinfo {
|
||||
$mods[$cmid]->availability = $rawmods[$cmid]->availability;
|
||||
$mods[$cmid]->deletioninprogress = $rawmods[$cmid]->deletioninprogress;
|
||||
$mods[$cmid]->downloadcontent = $rawmods[$cmid]->downloadcontent;
|
||||
$mods[$cmid]->lang = $rawmods[$cmid]->lang;
|
||||
|
||||
$modname = $mods[$cmid]->mod;
|
||||
$functionname = $modname . "_get_coursemodule_info";
|
||||
@@ -1110,6 +1111,7 @@ class course_modinfo {
|
||||
* @property-read string $afterediticons Extra HTML code to display after editing icons (e.g. more icons) - calculated on request
|
||||
* @property-read bool $deletioninprogress True if this course module is scheduled for deletion, false otherwise.
|
||||
* @property-read bool $downloadcontent True if content download is enabled for this course module, false otherwise.
|
||||
* @property-read bool $lang the forced language for this activity (language pack name). Null means not forced.
|
||||
*/
|
||||
class cm_info implements IteratorAggregate {
|
||||
/**
|
||||
@@ -1433,12 +1435,17 @@ class cm_info implements IteratorAggregate {
|
||||
*/
|
||||
private $downloadcontent;
|
||||
|
||||
/**
|
||||
* @var string|null the forced language for this activity (language pack name). Null means not forced.
|
||||
*/
|
||||
private $lang;
|
||||
|
||||
/**
|
||||
* List of class read-only properties and their getter methods.
|
||||
* Used by magic functions __get(), __isset(), __empty()
|
||||
* @var array
|
||||
*/
|
||||
private static $standardproperties = array(
|
||||
private static $standardproperties = [
|
||||
'url' => 'get_url',
|
||||
'content' => 'get_content',
|
||||
'extraclasses' => 'get_extra_classes',
|
||||
@@ -1488,8 +1495,9 @@ class cm_info implements IteratorAggregate {
|
||||
'visibleoncoursepage' => false,
|
||||
'visibleold' => false,
|
||||
'deletioninprogress' => false,
|
||||
'downloadcontent' => false
|
||||
);
|
||||
'downloadcontent' => false,
|
||||
'lang' => false,
|
||||
];
|
||||
|
||||
/**
|
||||
* List of methods with no arguments that were public prior to Moodle 2.6.
|
||||
@@ -1948,7 +1956,7 @@ class cm_info implements IteratorAggregate {
|
||||
static $cmfields = array('id', 'course', 'module', 'instance', 'section', 'idnumber', 'added',
|
||||
'score', 'indent', 'visible', 'visibleoncoursepage', 'visibleold', 'groupmode', 'groupingid',
|
||||
'completion', 'completiongradeitemnumber', 'completionview', 'completionexpected', 'completionpassgrade',
|
||||
'showdescription', 'availability', 'deletioninprogress', 'downloadcontent');
|
||||
'showdescription', 'availability', 'deletioninprogress', 'downloadcontent', 'lang');
|
||||
|
||||
foreach ($cmfields as $key) {
|
||||
$cmrecord->$key = $this->$key;
|
||||
@@ -2175,6 +2183,7 @@ class cm_info implements IteratorAggregate {
|
||||
$this->visibleold = isset($mod->visibleold) ? $mod->visibleold : 0;
|
||||
$this->deletioninprogress = isset($mod->deletioninprogress) ? $mod->deletioninprogress : 0;
|
||||
$this->downloadcontent = $mod->downloadcontent ?? null;
|
||||
$this->lang = $mod->lang ?? null;
|
||||
|
||||
// Note: it saves effort and database space to always include the
|
||||
// availability and completion fields, even if availability or completion
|
||||
|
||||
+8
-4
@@ -7087,7 +7087,7 @@ function clean_filename($string) {
|
||||
* @return string
|
||||
*/
|
||||
function current_language() {
|
||||
global $CFG, $USER, $SESSION, $COURSE;
|
||||
global $CFG, $PAGE, $SESSION, $USER;
|
||||
|
||||
if (!empty($SESSION->forcelang)) {
|
||||
// Allows overriding course-forced language (useful for admins to check
|
||||
@@ -7096,9 +7096,13 @@ function current_language() {
|
||||
// specific language (see force_current_language()).
|
||||
$return = $SESSION->forcelang;
|
||||
|
||||
} else if (!empty($COURSE->id) and $COURSE->id != SITEID and !empty($COURSE->lang)) {
|
||||
} else if (!empty($PAGE->cm->lang)) {
|
||||
// Activity language, if set.
|
||||
$return = $PAGE->cm->lang;
|
||||
|
||||
} else if (!empty($PAGE->course->id) && $PAGE->course->id != SITEID && !empty($PAGE->course->lang)) {
|
||||
// Course language can override all other settings for this page.
|
||||
$return = $COURSE->lang;
|
||||
$return = $PAGE->course->lang;
|
||||
|
||||
} else if (!empty($SESSION->lang)) {
|
||||
// Session language can override other settings.
|
||||
@@ -7151,7 +7155,7 @@ function force_current_language($language) {
|
||||
global $SESSION;
|
||||
$sessionforcelang = isset($SESSION->forcelang) ? $SESSION->forcelang : '';
|
||||
if ($language !== $sessionforcelang) {
|
||||
// Seting forcelang to null or an empty string disables it's effect.
|
||||
// Setting forcelang to null or an empty string disables its effect.
|
||||
if (empty($language) || get_string_manager()->translation_exists($language, false)) {
|
||||
$SESSION->forcelang = $language;
|
||||
moodle_setlocale();
|
||||
|
||||
@@ -949,12 +949,13 @@ EOD;
|
||||
/**
|
||||
* Assigns the specified role to a user in the context.
|
||||
*
|
||||
* @param int $roleid
|
||||
* @param int|string $role either an int role id or a string role shortname.
|
||||
* @param int $userid
|
||||
* @param int $contextid Defaults to the system context
|
||||
* @return int new/existing id of the assignment
|
||||
*/
|
||||
public function role_assign($roleid, $userid, $contextid = false) {
|
||||
public function role_assign($role, $userid, $contextid = false) {
|
||||
global $DB;
|
||||
|
||||
// Default to the system context.
|
||||
if (!$contextid) {
|
||||
@@ -962,15 +963,18 @@ EOD;
|
||||
$contextid = $context->id;
|
||||
}
|
||||
|
||||
if (empty($roleid)) {
|
||||
if (empty($role)) {
|
||||
throw new coding_exception('roleid must be present in testing_data_generator::role_assign() arguments');
|
||||
}
|
||||
if (!is_number($role)) {
|
||||
$role = $DB->get_field('role', 'id', ['shortname' => $role], MUST_EXIST);
|
||||
}
|
||||
|
||||
if (empty($userid)) {
|
||||
throw new coding_exception('userid must be present in testing_data_generator::role_assign() arguments');
|
||||
}
|
||||
|
||||
return role_assign($roleid, $userid, $contextid);
|
||||
return role_assign($role, $userid, $contextid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -268,8 +268,13 @@ abstract class testing_module_generator extends component_generator_base {
|
||||
debugging('Did you forget to enable completion tracking for the course before generating module with completion tracking?', DEBUG_DEVELOPER);
|
||||
}
|
||||
|
||||
if (!empty($record->lang) && !has_capability('moodle/course:setforcedlanguage', context_course::instance($course->id))) {
|
||||
throw new coding_exception('Attempt to generate an activity when the current user does not have ' .
|
||||
'permission moodle/course:setforcedlanguage. This does not work.');
|
||||
}
|
||||
|
||||
// Add the module to the course.
|
||||
$moduleinfo = add_moduleinfo($record, $course, $mform = null);
|
||||
$moduleinfo = add_moduleinfo($record, $course);
|
||||
|
||||
// Prepare object to return with additional field cmid.
|
||||
$instance = $DB->get_record($this->get_modulename(), array('id' => $moduleinfo->instance), '*', MUST_EXIST);
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
<?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 current_language() in moodlelib.php.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @copyright 2022 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core;
|
||||
|
||||
use moodle_page;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Unit tests for current_language() in moodlelib.php.
|
||||
*
|
||||
* @copyright 2022 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers ::current_language
|
||||
*/
|
||||
class moodlelib_current_language_test extends \advanced_testcase {
|
||||
|
||||
public function test_current_language_site_default(): void {
|
||||
$this->resetAfterTest();
|
||||
testable_string_manager_for_current_language_tests::set_fake_list_of_installed_languages(
|
||||
['en' => 'English', 'en_ar' => 'English (pirate)']);
|
||||
|
||||
set_config('lang', 'en_ar');
|
||||
|
||||
$this->assertEquals('en_ar', current_language());
|
||||
|
||||
testable_string_manager_for_current_language_tests::reset_installed_languages_override();
|
||||
}
|
||||
|
||||
public function test_current_language_user_pref(): void {
|
||||
$this->resetAfterTest();
|
||||
testable_string_manager_for_current_language_tests::set_fake_list_of_installed_languages(
|
||||
['en' => 'English', 'en_ar' => 'English (pirate)', 'fr' => 'French']);
|
||||
|
||||
set_config('lang', 'en_ar');
|
||||
$this->setUser($this->getDataGenerator()->create_user(['lang' => 'fr']));
|
||||
|
||||
$this->assertEquals('fr', current_language());
|
||||
|
||||
testable_string_manager_for_current_language_tests::reset_installed_languages_override();
|
||||
}
|
||||
|
||||
public function test_current_language_forced(): void {
|
||||
$this->resetAfterTest();
|
||||
testable_string_manager_for_current_language_tests::set_fake_list_of_installed_languages(
|
||||
['en' => 'English', 'en_ar' => 'English (pirate)', 'fr' => 'French', 'de' => 'German']);
|
||||
|
||||
set_config('lang', 'en_ar');
|
||||
$this->setUser($this->getDataGenerator()->create_user(['lang' => 'fr']));
|
||||
force_current_language('en');
|
||||
|
||||
$this->assertEquals('en', current_language());
|
||||
}
|
||||
|
||||
public function test_current_language_course_setting(): void {
|
||||
global $PAGE;
|
||||
$this->resetAfterTest();
|
||||
testable_string_manager_for_current_language_tests::set_fake_list_of_installed_languages(
|
||||
['en' => 'English', 'en_ar' => 'English (pirate)', 'fr' => 'French']);
|
||||
|
||||
set_config('lang', 'en_ar');
|
||||
$this->setUser($this->getDataGenerator()->create_user(['lang' => 'fr']));
|
||||
$PAGE = new moodle_page();
|
||||
$PAGE->set_course($this->getDataGenerator()->create_course(['lang' => 'de']));
|
||||
|
||||
$this->assertEquals('de', current_language());
|
||||
|
||||
testable_string_manager_for_current_language_tests::reset_installed_languages_override();
|
||||
}
|
||||
|
||||
public function test_current_language_in_course_no_lang_set(): void {
|
||||
global $PAGE;
|
||||
$this->resetAfterTest();
|
||||
testable_string_manager_for_current_language_tests::set_fake_list_of_installed_languages(
|
||||
['en' => 'English', 'en_ar' => 'English (pirate)', 'fr' => 'French']);
|
||||
|
||||
set_config('lang', 'en_ar');
|
||||
$PAGE = new moodle_page();
|
||||
$PAGE->set_course($this->getDataGenerator()->create_course());
|
||||
|
||||
$this->assertEquals('en_ar', current_language());
|
||||
|
||||
testable_string_manager_for_current_language_tests::reset_installed_languages_override();
|
||||
}
|
||||
|
||||
public function test_current_language_activity_setting(): void {
|
||||
global $PAGE;
|
||||
$this->resetAfterTest();
|
||||
testable_string_manager_for_current_language_tests::set_fake_list_of_installed_languages(
|
||||
['en' => 'English', 'en_ar' => 'English (pirate)', 'fr' => 'French']);
|
||||
|
||||
$this->setAdminUser();
|
||||
$course = $this->getDataGenerator()->create_course(['lang' => 'de']);
|
||||
$pageactivity = $this->getDataGenerator()->create_module('page', ['course' => $course->id, 'lang' => 'en']);
|
||||
$cm = get_fast_modinfo($course)->get_cm($pageactivity->cmid);
|
||||
|
||||
set_config('lang', 'en_ar');
|
||||
$this->setUser($this->getDataGenerator()->create_user(['lang' => 'fr']));
|
||||
$PAGE = new moodle_page();
|
||||
$PAGE->set_cm($cm, $course, $pageactivity);
|
||||
|
||||
$this->assertEquals('en', current_language());
|
||||
|
||||
testable_string_manager_for_current_language_tests::reset_installed_languages_override();
|
||||
}
|
||||
|
||||
public function test_current_language_activity_setting_not_set(): void {
|
||||
global $PAGE;
|
||||
$this->resetAfterTest();
|
||||
testable_string_manager_for_current_language_tests::set_fake_list_of_installed_languages(
|
||||
['en' => 'English', 'en_ar' => 'English (pirate)', 'fr' => 'French']);
|
||||
|
||||
$this->setAdminUser();
|
||||
$course = $this->getDataGenerator()->create_course(['lang' => 'de']);
|
||||
$pageactivity = $this->getDataGenerator()->create_module('page', ['course' => $course->id]);
|
||||
$cm = get_fast_modinfo($course)->get_cm($pageactivity->cmid);
|
||||
|
||||
set_config('lang', 'en_ar');
|
||||
$this->setUser($this->getDataGenerator()->create_user(['lang' => 'fr']));
|
||||
$PAGE = new moodle_page();
|
||||
$PAGE->set_cm($cm, $course, $pageactivity);
|
||||
|
||||
$this->assertEquals('de', current_language());
|
||||
|
||||
testable_string_manager_for_current_language_tests::reset_installed_languages_override();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test helper class for test which need Moodle to think there are other languages installed.
|
||||
*
|
||||
* @copyright 2022 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class testable_string_manager_for_current_language_tests extends \core_string_manager_standard {
|
||||
|
||||
/** @var array $installedlanguages list of languages which we want to pretend are installed. */
|
||||
protected $installedlanguages;
|
||||
|
||||
/**
|
||||
* Start pretending that the list of installed languages is other than what it is.
|
||||
*
|
||||
* You need to pass in an array like ['en' => 'English', 'fr' => 'French'].
|
||||
*
|
||||
* @param array $installedlanguages the list of languages to assume are installed.
|
||||
*/
|
||||
public static function set_fake_list_of_installed_languages(array $installedlanguages): void {
|
||||
global $CFG;
|
||||
|
||||
// Re-create the custom string-manager instance using this class, and force the thing we are overriding.
|
||||
$oldsetting = $CFG->config_php_settings['customstringmanager'] ?? null;
|
||||
$CFG->config_php_settings['customstringmanager'] = self::class;
|
||||
get_string_manager(true)->installedlanguages = $installedlanguages;
|
||||
|
||||
// Reset the setting we overrode.
|
||||
unset($CFG->config_php_settings['customstringmanager']);
|
||||
if ($oldsetting) {
|
||||
$CFG->config_php_settings['customstringmanager'] = $oldsetting;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be called at the end of any test which called set_fake_list_of_installed_languages to reset things.
|
||||
*/
|
||||
public static function reset_installed_languages_override(): void {
|
||||
get_string_manager(true);
|
||||
}
|
||||
|
||||
public function get_list_of_translations($returnall = false) {
|
||||
return $this->installedlanguages;
|
||||
}
|
||||
}
|
||||
@@ -160,7 +160,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$this->assertCount(1, $books['books']);
|
||||
$this->assertEquals('First Book', $books['books'][0]['name']);
|
||||
// We see 10 fields.
|
||||
$this->assertCount(10, $books['books'][0]);
|
||||
$this->assertCount(11, $books['books'][0]);
|
||||
|
||||
// As Student you cannot see some book properties like 'section'.
|
||||
$this->assertFalse(isset($books['books'][0]['section']));
|
||||
@@ -182,7 +182,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$this->assertCount(1, $books['books']);
|
||||
$this->assertEquals('Second Book', $books['books'][0]['name']);
|
||||
// We see 17 fields.
|
||||
$this->assertCount(17, $books['books'][0]);
|
||||
$this->assertCount(18, $books['books'][0]);
|
||||
// As an Admin you can see some book properties like 'section'.
|
||||
$this->assertEquals(0, $books['books'][0]['section']);
|
||||
|
||||
|
||||
@@ -218,7 +218,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
* Test get_chats_by_courses
|
||||
*/
|
||||
public function test_get_chats_by_courses() {
|
||||
global $DB, $USER, $CFG;
|
||||
global $DB, $CFG;
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
@@ -250,7 +250,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$this->assertCount(1, $chats['chats']);
|
||||
$this->assertEquals('First Chat', $chats['chats'][0]['name']);
|
||||
// We see 12 fields.
|
||||
$this->assertCount(12, $chats['chats'][0]);
|
||||
$this->assertCount(13, $chats['chats'][0]);
|
||||
|
||||
// As Student you cannot see some chat properties like 'section'.
|
||||
$this->assertFalse(isset($chats['chats'][0]['section']));
|
||||
@@ -273,7 +273,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$this->assertEquals('Second Chat', $chats['chats'][0]['name']);
|
||||
$this->assertEquals('header_js', $chats['chats'][0]['chatmethod']);
|
||||
// We see 17 fields.
|
||||
$this->assertCount(17, $chats['chats'][0]);
|
||||
$this->assertCount(18, $chats['chats'][0]);
|
||||
// As an Admin you can see some chat properties like 'section'.
|
||||
$this->assertEquals(0, $chats['chats'][0]['section']);
|
||||
|
||||
|
||||
@@ -58,6 +58,11 @@ class database_summary_exporter extends exporter {
|
||||
'type' => PARAM_INT,
|
||||
'default' => FORMAT_MOODLE
|
||||
),
|
||||
'lang' => array(
|
||||
'type' => PARAM_LANG,
|
||||
'description' => 'Forced activity language',
|
||||
'null' => NULL_ALLOWED,
|
||||
),
|
||||
'comments' => array(
|
||||
'type' => PARAM_BOOL,
|
||||
'description' => 'comments enabled',
|
||||
|
||||
@@ -178,15 +178,19 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
// First for the student user.
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'comments', 'timeavailablefrom',
|
||||
'timeavailableto', 'timeviewfrom', 'timeviewto', 'requiredentries', 'requiredentriestoview',
|
||||
'intro', 'introformat', 'introfiles', 'maxentries', 'rssarticles', 'singletemplate', 'listtemplate',
|
||||
'intro', 'introformat', 'introfiles', 'lang',
|
||||
'maxentries', 'rssarticles', 'singletemplate', 'listtemplate',
|
||||
'listtemplateheader', 'listtemplatefooter', 'addtemplate', 'rsstemplate', 'rsstitletemplate',
|
||||
'csstemplate', 'jstemplate', 'asearchtemplate', 'approval', 'defaultsort', 'defaultsortdir', 'manageapproved');
|
||||
'csstemplate', 'jstemplate', 'asearchtemplate', 'approval',
|
||||
'defaultsort', 'defaultsortdir', 'manageapproved');
|
||||
|
||||
// Add expected coursemodule.
|
||||
$database1->coursemodule = $database1->cmid;
|
||||
$database1->introfiles = [];
|
||||
$database1->lang = '';
|
||||
$database2->coursemodule = $database2->cmid;
|
||||
$database2->introfiles = [];
|
||||
$database2->lang = '';
|
||||
|
||||
$expected1 = array();
|
||||
$expected2 = array();
|
||||
|
||||
@@ -62,6 +62,11 @@ class feedback_summary_exporter extends exporter {
|
||||
'default' => FORMAT_MOODLE,
|
||||
'description' => 'Feedback intro text format.',
|
||||
),
|
||||
'lang' => array(
|
||||
'type' => PARAM_LANG,
|
||||
'description' => 'Forced activity language',
|
||||
'null' => NULL_ALLOWED,
|
||||
),
|
||||
'anonymous' => array(
|
||||
'type' => PARAM_INT,
|
||||
'description' => 'Whether the feedback is anonymous.',
|
||||
|
||||
+3
-2
@@ -107,7 +107,6 @@ class external_test extends externallib_advanced_testcase {
|
||||
* Test test_mod_feedback_get_feedbacks_by_courses
|
||||
*/
|
||||
public function test_mod_feedback_get_feedbacks_by_courses() {
|
||||
global $DB;
|
||||
|
||||
// Create additional course.
|
||||
$course2 = self::getDataGenerator()->create_course();
|
||||
@@ -134,7 +133,7 @@ class external_test extends externallib_advanced_testcase {
|
||||
|
||||
// Create what we expect to be returned when querying the two courses.
|
||||
// First for the student user.
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'anonymous',
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'lang', 'anonymous',
|
||||
'multiple_submit', 'autonumbering', 'page_after_submitformat', 'publish_stats', 'completionsubmit');
|
||||
|
||||
$properties = feedback_summary_exporter::read_properties_definition();
|
||||
@@ -144,10 +143,12 @@ class external_test extends externallib_advanced_testcase {
|
||||
$feedback1->coursemodule = $feedback1->cmid;
|
||||
$feedback1->introformat = 1;
|
||||
$feedback1->introfiles = [];
|
||||
$feedback1->lang = '';
|
||||
|
||||
$feedback2->coursemodule = $feedback2->cmid;
|
||||
$feedback2->introformat = 1;
|
||||
$feedback2->introfiles = [];
|
||||
$feedback2->lang = '';
|
||||
|
||||
foreach ($expectedfields as $field) {
|
||||
if (!empty($properties[$field]) && $properties[$field]['type'] == PARAM_BOOL) {
|
||||
|
||||
@@ -149,7 +149,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$returndescription = mod_folder_external::get_folders_by_courses_returns();
|
||||
|
||||
// Create what we expect to be returned when querying the two courses.
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'revision',
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'lang', 'revision',
|
||||
'timemodified', 'display', 'showexpanded', 'showdownloadfolder', 'section', 'visible',
|
||||
'forcedownload', 'groupmode', 'groupingid');
|
||||
|
||||
@@ -161,6 +161,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$folder1->groupmode = 0;
|
||||
$folder1->groupingid = 0;
|
||||
$folder1->introfiles = [];
|
||||
$folder1->lang = '';
|
||||
|
||||
$folder2->coursemodule = $folder2->cmid;
|
||||
$folder2->introformat = 1;
|
||||
@@ -169,6 +170,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$folder2->groupmode = 0;
|
||||
$folder2->groupingid = 0;
|
||||
$folder2->introfiles = [];
|
||||
$folder2->lang = '';
|
||||
|
||||
foreach ($expectedfields as $field) {
|
||||
$expected1[$field] = $folder1->{$field};
|
||||
|
||||
@@ -97,6 +97,8 @@ class mod_forum_external extends external_api {
|
||||
list($forum->intro, $forum->introformat) =
|
||||
external_format_text($forum->intro, $forum->introformat, $context->id, 'mod_forum', 'intro', null, $options);
|
||||
$forum->introfiles = external_util::get_area_files($context->id, 'mod_forum', 'intro', false, false);
|
||||
$forum->lang = clean_param($forum->lang, PARAM_LANG);
|
||||
|
||||
// Discussions count. This function does static request cache.
|
||||
$forum->numdiscussions = forum_count_discussions($forum, $cm, $course);
|
||||
$forum->cmid = $forum->coursemodule;
|
||||
@@ -134,6 +136,7 @@ class mod_forum_external extends external_api {
|
||||
'intro' => new external_value(PARAM_RAW, 'The forum intro'),
|
||||
'introformat' => new external_format_value('intro'),
|
||||
'introfiles' => new external_files('Files in the introduction text', VALUE_OPTIONAL),
|
||||
'lang' => new external_value(PARAM_SAFEDIR, 'Forced activity language', VALUE_OPTIONAL),
|
||||
'duedate' => new external_value(PARAM_INT, 'duedate for the user', VALUE_OPTIONAL),
|
||||
'cutoffdate' => new external_value(PARAM_INT, 'cutoffdate for the user', VALUE_OPTIONAL),
|
||||
'assessed' => new external_value(PARAM_INT, 'Aggregate type'),
|
||||
|
||||
@@ -145,6 +145,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$forum1->istracked = true;
|
||||
$forum1->unreadpostscount = 0;
|
||||
$forum1->introfiles = [];
|
||||
$forum1->lang = '';
|
||||
|
||||
$record = new \stdClass();
|
||||
$record->course = $course2->id;
|
||||
@@ -157,6 +158,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
// Default limited role, no create discussion capability enabled.
|
||||
$forum2->cancreatediscussions = false;
|
||||
$forum2->istracked = false;
|
||||
$forum2->lang = '';
|
||||
|
||||
// Check the forum was correctly created.
|
||||
$this->assertEquals(2, $DB->count_records_select('forum', 'id = :forum1 OR id = :forum2',
|
||||
|
||||
@@ -78,7 +78,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
|
||||
// Create what we expect to be returned when querying the two courses.
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'timemodified',
|
||||
'section', 'visible', 'groupmode', 'groupingid');
|
||||
'section', 'visible', 'groupmode', 'groupingid', 'lang');
|
||||
|
||||
// Add expected coursemodule and data.
|
||||
$label1->coursemodule = $label1->cmid;
|
||||
@@ -88,6 +88,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$label1->groupmode = 0;
|
||||
$label1->groupingid = 0;
|
||||
$label1->introfiles = [];
|
||||
$label1->lang = '';
|
||||
|
||||
$label2->coursemodule = $label2->cmid;
|
||||
$label2->introformat = 1;
|
||||
@@ -96,6 +97,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$label2->groupmode = 0;
|
||||
$label2->groupingid = 0;
|
||||
$label2->introfiles = [];
|
||||
$label2->lang = '';
|
||||
|
||||
foreach ($expectedfields as $field) {
|
||||
$expected1[$field] = $label1->{$field};
|
||||
|
||||
@@ -54,6 +54,7 @@ class mod_lesson_external extends external_api {
|
||||
|
||||
$lesson = new lesson($lessonrecord);
|
||||
$lesson->update_effective_access($USER->id);
|
||||
$lessonrecord->lang = $lesson->get_cm()->lang;
|
||||
$lessonavailable = $lesson->get_time_restriction_status() === false;
|
||||
$lessonavailable = $lessonavailable && $lesson->get_password_restriction_status($password) === false;
|
||||
$lessonavailable = $lessonavailable && $lesson->get_dependencies_restriction_status() === false;
|
||||
|
||||
@@ -66,6 +66,11 @@ class lesson_summary_exporter extends exporter {
|
||||
'type' => PARAM_INT,
|
||||
'default' => FORMAT_MOODLE
|
||||
),
|
||||
'lang' => array(
|
||||
'type' => PARAM_LANG,
|
||||
'description' => 'Forced activity language',
|
||||
'null' => NULL_ALLOWED,
|
||||
),
|
||||
'practice' => array(
|
||||
'type' => PARAM_BOOL,
|
||||
'description' => 'Practice lesson?',
|
||||
|
||||
+8
-6
@@ -142,8 +142,8 @@ class external_test extends externallib_advanced_testcase {
|
||||
|
||||
// Create what we expect to be returned when querying the two courses.
|
||||
// First for the student user.
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'practice',
|
||||
'modattempts', 'usepassword', 'grade', 'custom', 'ongoing', 'usemaxgrade',
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'lang',
|
||||
'practice', 'modattempts', 'usepassword', 'grade', 'custom', 'ongoing', 'usemaxgrade',
|
||||
'maxanswers', 'maxattempts', 'review', 'nextpagedefault', 'feedback', 'minquestions',
|
||||
'maxpages', 'timelimit', 'retake', 'mediafile', 'mediafiles', 'mediaheight', 'mediawidth',
|
||||
'mediaclose', 'slideshow', 'width', 'height', 'bgcolor', 'displayleft', 'displayleftif',
|
||||
@@ -155,11 +155,13 @@ class external_test extends externallib_advanced_testcase {
|
||||
$lesson1->introformat = 1;
|
||||
$lesson1->introfiles = [];
|
||||
$lesson1->mediafiles = [];
|
||||
$lesson1->lang = '';
|
||||
|
||||
$lesson2->coursemodule = $lesson2->cmid;
|
||||
$lesson2->introformat = 1;
|
||||
$lesson2->introfiles = [];
|
||||
$lesson2->mediafiles = [];
|
||||
$lesson2->lang = '';
|
||||
|
||||
$booltypes = array('practice', 'modattempts', 'usepassword', 'custom', 'ongoing', 'review', 'feedback', 'retake',
|
||||
'slideshow', 'displayleft', 'progressbar', 'allowofflineattempts');
|
||||
@@ -1322,7 +1324,7 @@ class external_test extends externallib_advanced_testcase {
|
||||
// Lesson not using password.
|
||||
$result = mod_lesson_external::get_lesson($this->lesson->id);
|
||||
$result = \external_api::clean_returnvalue(mod_lesson_external::get_lesson_returns(), $result);
|
||||
$this->assertCount(36, $result['lesson']); // Expect most of the fields.
|
||||
$this->assertCount(37, $result['lesson']); // Expect most of the fields.
|
||||
$this->assertFalse(isset($result['password']));
|
||||
}
|
||||
|
||||
@@ -1340,7 +1342,7 @@ class external_test extends externallib_advanced_testcase {
|
||||
// Lesson not using password.
|
||||
$result = mod_lesson_external::get_lesson($this->lesson->id);
|
||||
$result = \external_api::clean_returnvalue(mod_lesson_external::get_lesson_returns(), $result);
|
||||
$this->assertCount(6, $result['lesson']); // Expect just this few fields.
|
||||
$this->assertCount(7, $result['lesson']); // Expect just this few fields.
|
||||
$this->assertFalse(isset($result['intro']));
|
||||
}
|
||||
|
||||
@@ -1358,7 +1360,7 @@ class external_test extends externallib_advanced_testcase {
|
||||
// Lesson not using password.
|
||||
$result = mod_lesson_external::get_lesson($this->lesson->id, $password);
|
||||
$result = \external_api::clean_returnvalue(mod_lesson_external::get_lesson_returns(), $result);
|
||||
$this->assertCount(36, $result['lesson']);
|
||||
$this->assertCount(37 , $result['lesson']);
|
||||
$this->assertFalse(isset($result['intro']));
|
||||
}
|
||||
|
||||
@@ -1376,7 +1378,7 @@ class external_test extends externallib_advanced_testcase {
|
||||
// Lesson not passing a valid password (but we are teachers, we should see all the info).
|
||||
$result = mod_lesson_external::get_lesson($this->lesson->id);
|
||||
$result = \external_api::clean_returnvalue(mod_lesson_external::get_lesson_returns(), $result);
|
||||
$this->assertCount(45, $result['lesson']); // Expect all the fields.
|
||||
$this->assertCount(46, $result['lesson']); // Expect all the fields.
|
||||
$this->assertEquals($result['lesson']['password'], $password);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ class externallib_test extends mod_lti_testcase {
|
||||
|
||||
// Create what we expect to be returned when querying the two courses.
|
||||
// First for the student user.
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles',
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'lang',
|
||||
'launchcontainer', 'showtitlelaunch', 'showdescriptionlaunch', 'icon', 'secureicon');
|
||||
|
||||
// Add expected coursemodule and data.
|
||||
@@ -205,6 +205,7 @@ class externallib_test extends mod_lti_testcase {
|
||||
$lti1->groupingid = 0;
|
||||
$lti1->section = 0;
|
||||
$lti1->introfiles = [];
|
||||
$lti1->lang = '';
|
||||
|
||||
$lti2->coursemodule = $lti2->cmid;
|
||||
$lti2->introformat = 1;
|
||||
@@ -214,6 +215,7 @@ class externallib_test extends mod_lti_testcase {
|
||||
$lti2->groupingid = 0;
|
||||
$lti2->section = 0;
|
||||
$lti2->introfiles = [];
|
||||
$lti2->lang = '';
|
||||
|
||||
foreach ($expectedfields as $field) {
|
||||
$expected1[$field] = $lti1->{$field};
|
||||
@@ -257,7 +259,7 @@ class externallib_test extends mod_lti_testcase {
|
||||
$additionalfields = array('timecreated', 'timemodified', 'typeid', 'toolurl', 'securetoolurl',
|
||||
'instructorchoicesendname', 'instructorchoicesendemailaddr', 'instructorchoiceallowroster',
|
||||
'instructorchoiceallowsetting', 'instructorcustomparameters', 'instructorchoiceacceptgrades', 'grade',
|
||||
'resourcekey', 'password', 'debuglaunch', 'servicesalt', 'visible', 'groupmode', 'groupingid', 'section');
|
||||
'resourcekey', 'password', 'debuglaunch', 'servicesalt', 'visible', 'groupmode', 'groupingid', 'section', 'lang');
|
||||
|
||||
foreach ($additionalfields as $field) {
|
||||
$expectedltis[0][$field] = $lti1->{$field};
|
||||
|
||||
@@ -147,7 +147,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$returndescription = mod_page_external::get_pages_by_courses_returns();
|
||||
|
||||
// Create what we expect to be returned when querying the two courses.
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles',
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'lang',
|
||||
'content', 'contentformat', 'contentfiles', 'legacyfiles', 'legacyfileslast', 'display',
|
||||
'displayoptions', 'revision', 'timemodified', 'section', 'visible', 'groupmode', 'groupingid');
|
||||
|
||||
@@ -161,6 +161,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$page1->groupingid = 0;
|
||||
$page1->introfiles = [];
|
||||
$page1->contentfiles = [];
|
||||
$page1->lang = '';
|
||||
|
||||
$page2->coursemodule = $page2->cmid;
|
||||
$page2->introformat = 1;
|
||||
@@ -171,6 +172,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$page2->groupingid = 0;
|
||||
$page2->introfiles = [];
|
||||
$page2->contentfiles = [];
|
||||
$page2->lang = '';
|
||||
|
||||
foreach ($expectedfields as $field) {
|
||||
$expected1[$field] = $page1->{$field};
|
||||
|
||||
+5
-3
@@ -214,8 +214,8 @@ class external_test extends externallib_advanced_testcase {
|
||||
|
||||
// Create what we expect to be returned when querying the two courses.
|
||||
// First for the student user.
|
||||
$allusersfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'timeopen',
|
||||
'timeclose', 'grademethod', 'section', 'visible', 'groupmode', 'groupingid',
|
||||
$allusersfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'lang',
|
||||
'timeopen', 'timeclose', 'grademethod', 'section', 'visible', 'groupmode', 'groupingid',
|
||||
'attempts', 'timelimit', 'grademethod', 'decimalpoints', 'questiondecimalpoints', 'sumgrades',
|
||||
'grade', 'preferredbehaviour', 'hasfeedback');
|
||||
$userswithaccessfields = array('attemptonlast', 'reviewattempt', 'reviewcorrectness', 'reviewmarks',
|
||||
@@ -239,6 +239,7 @@ class external_test extends externallib_advanced_testcase {
|
||||
$quiz1->completionpass = 0;
|
||||
$quiz1->autosaveperiod = get_config('quiz', 'autosaveperiod');
|
||||
$quiz1->introfiles = [];
|
||||
$quiz1->lang = '';
|
||||
|
||||
$quiz2->coursemodule = $quiz2->cmid;
|
||||
$quiz2->introformat = 1;
|
||||
@@ -251,6 +252,7 @@ class external_test extends externallib_advanced_testcase {
|
||||
$quiz2->completionpass = 0;
|
||||
$quiz2->autosaveperiod = get_config('quiz', 'autosaveperiod');
|
||||
$quiz2->introfiles = [];
|
||||
$quiz2->lang = '';
|
||||
|
||||
foreach (array_merge($allusersfields, $userswithaccessfields) as $field) {
|
||||
$expected1[$field] = $quiz1->{$field};
|
||||
@@ -317,7 +319,7 @@ class external_test extends externallib_advanced_testcase {
|
||||
$result = \external_api::clean_returnvalue($returndescription, $result);
|
||||
$this->assertCount(2, $result['quizzes']);
|
||||
// We only see a limited set of fields.
|
||||
$this->assertCount(4, $result['quizzes'][0]);
|
||||
$this->assertCount(5, $result['quizzes'][0]);
|
||||
$this->assertEquals($quiz2->id, $result['quizzes'][0]['id']);
|
||||
$this->assertEquals($quiz2->cmid, $result['quizzes'][0]['coursemodule']);
|
||||
$this->assertEquals($quiz2->course, $result['quizzes'][0]['course']);
|
||||
|
||||
@@ -148,7 +148,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$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',
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'lang',
|
||||
'contentfiles', 'tobemigrated', 'legacyfiles', 'legacyfileslast', 'display', 'displayoptions',
|
||||
'filterfiles', 'revision', 'timemodified', 'section', 'visible', 'groupmode', 'groupingid');
|
||||
|
||||
@@ -162,6 +162,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$resource1->groupingid = 0;
|
||||
$resource1->introfiles = [];
|
||||
$resource1->contentfiles = [];
|
||||
$resource1->lang = '';
|
||||
|
||||
$resource2->coursemodule = $resource2->cmid;
|
||||
$resource2->introformat = 1;
|
||||
@@ -172,6 +173,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$resource2->groupingid = 0;
|
||||
$resource2->introfiles = [];
|
||||
$resource2->contentfiles = [];
|
||||
$resource2->lang = '';
|
||||
|
||||
foreach ($expectedfields as $field) {
|
||||
$expected1[$field] = $resource1->{$field};
|
||||
|
||||
@@ -647,7 +647,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$result = \external_api::clean_returnvalue($returndescription, $result);
|
||||
$this->assertCount(1, $result['warnings']);
|
||||
// Only 'id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles'.
|
||||
$this->assertCount(7, $result['scorms'][0]);
|
||||
$this->assertCount(8, $result['scorms'][0]);
|
||||
$this->assertEquals('expired', $result['warnings'][0]['warningcode']);
|
||||
|
||||
$scorm1->timeopen = $timenow + DAYSECS;
|
||||
@@ -658,7 +658,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$result = \external_api::clean_returnvalue($returndescription, $result);
|
||||
$this->assertCount(1, $result['warnings']);
|
||||
// Only 'id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles'.
|
||||
$this->assertCount(7, $result['scorms'][0]);
|
||||
$this->assertCount(8, $result['scorms'][0]);
|
||||
$this->assertEquals('notopenyet', $result['warnings'][0]['warningcode']);
|
||||
|
||||
// Reset times.
|
||||
@@ -668,7 +668,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
|
||||
// Create what we expect to be returned when querying the two courses.
|
||||
// First for the student user.
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'version', 'maxgrade',
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'lang', 'version', 'maxgrade',
|
||||
'grademethod', 'whatgrade', 'maxattempt', 'forcecompleted', 'forcenewattempt', 'lastattemptlock',
|
||||
'displayattemptstatus', 'displaycoursestructure', 'sha1hash', 'md5hash', 'revision', 'launch',
|
||||
'skipview', 'hidebrowse', 'hidetoc', 'nav', 'navpositionleft', 'navpositiontop', 'auto',
|
||||
@@ -681,12 +681,14 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$scorm1->visible = true;
|
||||
$scorm1->groupmode = 0;
|
||||
$scorm1->groupingid = 0;
|
||||
$scorm1->lang = '';
|
||||
|
||||
$scorm2->coursemodule = $scorm2->cmid;
|
||||
$scorm2->section = 0;
|
||||
$scorm2->visible = true;
|
||||
$scorm2->groupmode = 0;
|
||||
$scorm2->groupingid = 0;
|
||||
$scorm2->lang = '';
|
||||
|
||||
// SCORM size. The same package is used in both SCORMs.
|
||||
$scormcontext1 = \context_module::instance($scorm1->cmid);
|
||||
|
||||
@@ -96,8 +96,8 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
|
||||
// Create what we expect to be returned when querying the two courses.
|
||||
// First for the student user.
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'template', 'days',
|
||||
'questions', 'surveydone');
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'lang',
|
||||
'template', 'days', 'questions', 'surveydone');
|
||||
|
||||
// Add expected coursemodule and data.
|
||||
$survey1 = $this->survey;
|
||||
@@ -109,6 +109,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$survey1->groupmode = 0;
|
||||
$survey1->groupingid = 0;
|
||||
$survey1->introfiles = [];
|
||||
$survey1->lang = '';
|
||||
|
||||
$survey2->coursemodule = $survey2->cmid;
|
||||
$survey2->introformat = 1;
|
||||
@@ -120,6 +121,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$tempo = $DB->get_field("survey", "intro", array("id" => $survey2->template));
|
||||
$survey2->intro = nl2br(get_string($tempo, "survey"));
|
||||
$survey2->introfiles = [];
|
||||
$survey2->lang = '';
|
||||
|
||||
foreach ($expectedfields as $field) {
|
||||
$expected1[$field] = $survey1->{$field};
|
||||
|
||||
@@ -147,9 +147,9 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$returndescription = mod_url_external::get_urls_by_courses_returns();
|
||||
|
||||
// Create what we expect to be returned when querying the two courses.
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'externalurl',
|
||||
'display', 'displayoptions', 'parameters', 'timemodified', 'section', 'visible', 'groupmode',
|
||||
'groupingid');
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'lang',
|
||||
'externalurl', 'display', 'displayoptions', 'parameters', 'timemodified', 'section', 'visible', 'groupmode',
|
||||
'groupingid');
|
||||
|
||||
// Add expected coursemodule and data.
|
||||
$url1->coursemodule = $url1->cmid;
|
||||
@@ -159,6 +159,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$url1->groupmode = 0;
|
||||
$url1->groupingid = 0;
|
||||
$url1->introfiles = [];
|
||||
$url1->lang = '';
|
||||
|
||||
$url2->coursemodule = $url2->cmid;
|
||||
$url2->introformat = 1;
|
||||
@@ -167,6 +168,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$url2->groupmode = 0;
|
||||
$url2->groupingid = 0;
|
||||
$url2->introfiles = [];
|
||||
$url2->lang = '';
|
||||
|
||||
foreach ($expectedfields as $field) {
|
||||
$expected1[$field] = $url1->{$field};
|
||||
|
||||
@@ -168,9 +168,9 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
|
||||
// Create what we expect to be returned when querying the two courses.
|
||||
// First for the student user.
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'firstpagetitle',
|
||||
'wikimode', 'defaultformat', 'forceformat', 'editbegin', 'editend', 'section', 'visible',
|
||||
'groupmode', 'groupingid');
|
||||
$expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'lang',
|
||||
'firstpagetitle', 'wikimode', 'defaultformat', 'forceformat', 'editbegin', 'editend', 'section', 'visible',
|
||||
'groupmode', 'groupingid');
|
||||
|
||||
// Add expected coursemodule and data.
|
||||
$wiki1 = $this->wiki;
|
||||
@@ -181,6 +181,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$wiki1->groupmode = 0;
|
||||
$wiki1->groupingid = 0;
|
||||
$wiki1->introfiles = [];
|
||||
$wiki1->lang = '';
|
||||
|
||||
$wiki2->coursemodule = $wiki2->cmid;
|
||||
$wiki2->introformat = 1;
|
||||
@@ -189,6 +190,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$wiki2->groupmode = 0;
|
||||
$wiki2->groupingid = 0;
|
||||
$wiki2->introfiles = [];
|
||||
$wiki2->lang = '';
|
||||
|
||||
foreach ($expectedfields as $field) {
|
||||
$expected1[$field] = $wiki1->{$field};
|
||||
|
||||
@@ -64,6 +64,11 @@ class workshop_summary_exporter extends exporter {
|
||||
'default' => FORMAT_MOODLE,
|
||||
'description' => 'Workshop intro text format.',
|
||||
),
|
||||
'lang' => array(
|
||||
'type' => PARAM_LANG,
|
||||
'description' => 'Forced activity language',
|
||||
'null' => NULL_ALLOWED,
|
||||
),
|
||||
'instructauthors' => array(
|
||||
'type' => PARAM_RAW,
|
||||
'description' => 'Instructions for the submission phase.',
|
||||
|
||||
@@ -161,6 +161,7 @@ class external_test extends externallib_advanced_testcase {
|
||||
$workshop1->coursemodule = $workshop1->cmid;
|
||||
$workshop1->introformat = 1;
|
||||
$workshop1->introfiles = [];
|
||||
$workshop1->lang = '';
|
||||
$workshop1->instructauthorsfiles = [];
|
||||
$workshop1->instructauthorsformat = 1;
|
||||
$workshop1->instructreviewersfiles = [];
|
||||
@@ -173,6 +174,7 @@ class external_test extends externallib_advanced_testcase {
|
||||
$workshop2->coursemodule = $workshop2->cmid;
|
||||
$workshop2->introformat = 1;
|
||||
$workshop2->introfiles = [];
|
||||
$workshop2->lang = '';
|
||||
$workshop2->instructauthorsfiles = [];
|
||||
$workshop2->instructauthorsformat = 1;
|
||||
$workshop2->instructreviewersfiles = [];
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2022081200.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2022081200.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '4.1dev (Build: 20220812)'; // Human-friendly version name
|
||||
|
||||
Reference in New Issue
Block a user