Merge branch 'MOODLE_25_STABLE' into install_25_STABLE

This commit is contained in:
AMOS bot
2013-09-14 00:41:35 +00:00
48 changed files with 630 additions and 203 deletions
+2
View File
@@ -32,6 +32,7 @@ if (($hassiteconfig || has_any_capability(array(
'moodle/badges:createbadge',
'moodle/badges:manageglobalsettings',
'moodle/badges:awardbadge',
'moodle/badges:configurecriteria',
'moodle/badges:configuremessages',
'moodle/badges:configuredetails',
'moodle/badges:deletebadge'), $systemcontext))) {
@@ -74,6 +75,7 @@ if (($hassiteconfig || has_any_capability(array(
'moodle/badges:viewawarded',
'moodle/badges:createbadge',
'moodle/badges:awardbadge',
'moodle/badges:configurecriteria',
'moodle/badges:configuremessages',
'moodle/badges:configuredetails',
'moodle/badges:deletebadge'
+1
View File
@@ -38,6 +38,7 @@ $string['stepsdefinitionscontains'] = 'Contains';
$string['stepsdefinitionsfilters'] = 'Steps definitions';
$string['stepsdefinitionstype'] = 'Type';
$string['theninfo'] = 'Then. Checkings to ensure the outcomes are the expected ones';
$string['unknownexceptioninfo'] = 'There was a problem with Selenium or the browser, try to upgrade Selenium to the latest version. Error: ';
$string['viewsteps'] = 'Filter';
$string['wheninfo'] = 'When. Actions that provokes an event';
$string['wrongbehatsetup'] = 'Something is wrong with behat setup, ensure:<ul>
+1 -1
View File
@@ -137,7 +137,7 @@ class auth_plugin_cas extends auth_plugin_ldap {
// test pgtIou parameter for proxy mode (https connection
// in background from CAS server to the php server)
if ($authCAS != 'CAS' && !isset($_GET['pgtIou'])) {
$PAGE->set_url('/auth/cas/auth.php');
$PAGE->set_url('/login/index.php');
$PAGE->navbar->add($CASform);
$PAGE->set_title("$site->fullname: $CASform");
$PAGE->set_heading($site->fullname);
+2 -2
View File
@@ -35,13 +35,13 @@ $string['auth_dbfieldpass'] = 'Name of the field containing passwords';
$string['auth_dbfieldpass_key'] = 'Password field';
$string['auth_dbfielduser'] = 'Name of the field containing usernames';
$string['auth_dbfielduser_key'] = 'Username field';
$string['auth_dbhost'] = 'The computer hosting the database server.';
$string['auth_dbhost'] = 'The computer hosting the database server. Use a system DSN entry if using ODBC.';
$string['auth_dbhost_key'] = 'Host';
$string['auth_dbchangepasswordurl_key'] = 'Password-change URL';
$string['auth_dbinsertuser'] = 'Inserted user {$a->name} id {$a->id}';
$string['auth_dbinsertuserduplicate'] = 'Error inserting user {$a->username} - user with this username was already created through \'{$a->auth}\' plugin.';
$string['auth_dbinsertusererror'] = 'Error inserting user {$a}';
$string['auth_dbname'] = 'Name of the database itself';
$string['auth_dbname'] = 'Name of the database itself. Leave empty if using an ODBC DSN.';
$string['auth_dbname_key'] = 'DB name';
$string['auth_dbpass'] = 'Password matching the above username';
$string['auth_dbpass_key'] = 'Password';
@@ -335,6 +335,9 @@ class restore_controller extends backup implements loggable {
if ($this->status != backup::STATUS_NEED_PRECHECK) {
throw new restore_controller_exception('cannot_precheck_wrong_status', $this->status);
}
// Basic/initial prevention against time/memory limits
set_time_limit(1 * 60 * 60); // 1 hour for 1 course initially granted
raise_memory_limit(MEMORY_EXTRA);
$this->precheck = restore_prechecks_helper::execute_prechecks($this, $droptemptablesafter);
if (!array_key_exists('errors', $this->precheck)) { // No errors, can be executed
$this->set_status(backup::STATUS_AWAITING);
+15 -7
View File
@@ -475,8 +475,9 @@ class restore_ui_stage_schema extends restore_ui_stage {
if ($this->stageform === null) {
$form = new restore_schema_form($this, $PAGE->url);
$tasks = $this->ui->get_tasks();
$content = '';
$courseheading = false;
$allsettings = array();
foreach ($tasks as $task) {
if (!($task instanceof restore_root_task)) {
if (!$courseheading) {
@@ -484,13 +485,11 @@ class restore_ui_stage_schema extends restore_ui_stage {
$form->add_heading('coursesettings', get_string('coursesettings', 'backup'));
$courseheading = true;
}
// First add each setting
// Put each setting into an array of settings to add. Adding
// a setting individually is a very slow operation, so we add
// them all in a batch later on.
foreach ($task->get_settings() as $setting) {
$form->add_setting($setting, $task);
}
// The add all the dependencies
foreach ($task->get_settings() as $setting) {
$form->add_dependencies($setting);
$allsettings[] = array($setting, $task);
}
} else if ($this->ui->enforce_changed_dependencies()) {
// Only show these settings if dependencies changed them.
@@ -505,6 +504,15 @@ class restore_ui_stage_schema extends restore_ui_stage {
}
}
}
// Actually add all the settings that we put in the array.
$form->add_settings($allsettings);
// Add the dependencies for all the settings.
foreach ($allsettings as $settingtask) {
$form->add_dependencies($settingtask[0]);
}
$this->stageform = $form;
}
return $this->stageform;
+5 -1
View File
@@ -95,7 +95,11 @@ if ($copy) {
require_capability('moodle/badges:createbadge', $context);
$cloneid = $badge->make_clone();
redirect(new moodle_url('/badges/edit.php', array('id' => $cloneid, 'action' => 'details')));
// If a user can edit badge details, they will be redirected to the edit page.
if (has_capability('moodle/badges:configuredetails', $context)) {
redirect(new moodle_url('/badges/edit.php', array('id' => $cloneid, 'action' => 'details')));
}
redirect(new moodle_url('/badges/overview.php', array('id' => $cloneid)));
}
if ($activate) {
+2 -1
View File
@@ -40,6 +40,8 @@ $badge = new badge($badgeid);
$context = $badge->get_context();
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type));
require_capability('moodle/badges:configurecriteria', $context);
if ($badge->type == BADGE_TYPE_COURSE) {
if (empty($CFG->badges_allowcoursebadges)) {
print_error('coursebadgesdisabled', 'badges');
@@ -66,7 +68,6 @@ $emsg = optional_param('emsg', '', PARAM_TEXT);
if ((($update == BADGE_CRITERIA_AGGREGATION_ALL) || ($update == BADGE_CRITERIA_AGGREGATION_ANY))) {
require_sesskey();
require_capability('moodle/badges:configurecriteria', $context);
$obj = new stdClass();
$obj->id = $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->id;
$obj->method = $update;
+5 -1
View File
@@ -41,7 +41,11 @@ $badge = new badge($badgeid);
$context = $badge->get_context();
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type));
require_capability('moodle/badges:configuredetails', $context);
if ($action == 'message') {
require_capability('moodle/badges:configuremessages', $context);
} else {
require_capability('moodle/badges:configuredetails', $context);
}
if ($badge->type == BADGE_TYPE_COURSE) {
if (empty($CFG->badges_allowcoursebadges)) {
+5 -1
View File
@@ -99,7 +99,11 @@ if ($form->is_cancelled()) {
$newbadge = new badge($newid);
badges_process_badge_image($newbadge, $form->save_temp_file('image'));
redirect(new moodle_url('/badges/criteria.php', array('id' => $newid)));
// If a user can configure badge criteria, they will be redirected to the criteria page.
if (has_capability('moodle/badges:configurecriteria', $PAGE->context)) {
redirect(new moodle_url('/badges/criteria.php', array('id' => $newid)));
}
redirect(new moodle_url('/badges/overview.php', array('id' => $newid)));
}
echo $OUTPUT->header();
+9
View File
@@ -0,0 +1,9 @@
/* RSS Feeds
-------------------------*/
.block_rss_client .list li:first-child {
border-top-width: 0;
}
.block_rss_client .list li {
border-top: 1px solid;
padding: 5px;
}
+13 -9
View File
@@ -326,19 +326,23 @@ class course_edit_form extends moodleform {
/// perform some extra moodle validation
function validation($data, $files) {
global $DB, $CFG;
global $DB;
$errors = parent::validation($data, $files);
if ($foundcourses = $DB->get_records('course', array('shortname'=>$data['shortname']))) {
if (!empty($data['id'])) {
unset($foundcourses[$data['id']]);
// Add field validation check for duplicate shortname.
if ($course = $DB->get_record('course', array('shortname' => $data['shortname']), '*', IGNORE_MULTIPLE)) {
if (empty($data['id']) || $course->id != $data['id']) {
$errors['shortname'] = get_string('shortnametaken', '', $course->fullname);
}
if (!empty($foundcourses)) {
foreach ($foundcourses as $foundcourse) {
$foundcoursenames[] = $foundcourse->fullname;
}
// Add field validation check for duplicate idnumber.
if (!empty($data['idnumber']) && (empty($data['id']) || $this->course->idnumber != $data['idnumber'])) {
if ($course = $DB->get_record('course', array('idnumber' => $data['idnumber']), '*', IGNORE_MULTIPLE)) {
if (empty($data['id']) || $course->id != $data['id']) {
$errors['idnumber'] = get_string('idnumbertaken', 'error');
}
$foundcoursenamestring = implode(',', $foundcoursenames);
$errors['shortname']= get_string('shortnametaken', '', $foundcoursenamestring);
}
}
+2 -8
View File
@@ -717,20 +717,14 @@ class core_course_external extends external_api {
require_capability('moodle/course:changefullname', $context);
}
// Check if the shortname already exist and user have capability.
// Check if the user can change shortname.
if (array_key_exists('shortname', $course) && ($oldcourse->shortname != $course['shortname'])) {
require_capability('moodle/course:changeshortname', $context);
if ($DB->record_exists('course', array('shortname' => $course['shortname']))) {
throw new moodle_exception('shortnametaken');
}
}
// Check if the id number already exist and user have capability.
// Check if the user can change the idnumber.
if (array_key_exists('idnumber', $course) && ($oldcourse->idnumber != $course['idnumber'])) {
require_capability('moodle/course:changeidnumber', $context);
if ($DB->record_exists('course', array('idnumber' => $course['idnumber']))) {
throw new moodle_exception('idnumbertaken');
}
}
// Check if user can change summary.
+18 -1
View File
@@ -2362,6 +2362,20 @@ function update_course($data, $editoroptions = NULL) {
$data = file_postupdate_standard_filemanager($data, 'overviewfiles', $overviewfilesoptions, $context, 'course', 'overviewfiles', 0);
}
// Check we don't have a duplicate shortname.
if (!empty($data->shortname) && $oldcourse->shortname != $data->shortname) {
if ($DB->record_exists('course', array('shortname' => $data->shortname))) {
throw new moodle_exception('shortnametaken', '', '', $data->shortname);
}
}
// Check we don't have a duplicate idnumber.
if (!empty($data->idnumber) && $oldcourse->idnumber != $data->idnumber) {
if ($DB->record_exists('course', array('idnumber' => $data->idnumber))) {
throw new moodle_exception('idnumbertaken', 'error');
}
}
if (!isset($data->category) or empty($data->category)) {
// prevent nulls and 0 in category field
unset($data->category);
@@ -2402,7 +2416,10 @@ function update_course($data, $editoroptions = NULL) {
context_moved($context, $newparent);
}
fix_course_sortorder();
if ($movecat || (isset($data->sortorder) && $oldcourse->sortorder != $data->sortorder)) {
fix_course_sortorder();
}
// purge appropriate caches in case fix_course_sortorder() did not change anything
cache_helper::purge_by_event('changesincourse');
if ($changesincoursecat) {
+46
View File
@@ -635,6 +635,52 @@ class courselib_testcase extends advanced_testcase {
$this->assertEquals(range(0, $course->numsections + 1), $sectionscreated);
}
public function test_update_course() {
global $DB;
$this->resetAfterTest();
$defaultcategory = $DB->get_field_select('course_categories', "MIN(id)", "parent=0");
$course = new stdClass();
$course->fullname = 'Apu loves Unit Təsts';
$course->shortname = 'test1';
$course->idnumber = '1';
$course->summary = 'Awesome!';
$course->summaryformat = FORMAT_PLAIN;
$course->format = 'topics';
$course->newsitems = 0;
$course->numsections = 5;
$course->category = $defaultcategory;
$created = create_course($course);
// Ensure the checks only work on idnumber/shortname that are not already ours.
update_course($created);
$course->shortname = 'test2';
$course->idnumber = '2';
$created2 = create_course($course);
// Test duplicate idnumber.
$created2->idnumber = '1';
try {
update_course($created2);
$this->fail('Expected exception when trying to update a course with duplicate idnumber');
} catch (moodle_exception $e) {
$this->assertEquals(get_string('idnumbertaken', 'error'), $e->getMessage());
}
// Test duplicate shortname.
$created2->idnumber = '2';
$created2->shortname = 'test1';
try {
update_course($created2);
$this->fail('Expected exception when trying to update a course with a duplicate shortname');
} catch (moodle_exception $e) {
$this->assertEquals(get_string('shortnametaken', 'error', $created2->shortname), $e->getMessage());
}
}
public function test_course_add_cm_to_section() {
global $DB;
$this->resetAfterTest(true);
+2 -1
View File
@@ -25,8 +25,9 @@
$string['database:unenrol'] = 'Unenrol suspended users';
$string['dbencoding'] = 'Database encoding';
$string['dbhost'] = 'Database host';
$string['dbhost_desc'] = 'Type database server IP address or host name';
$string['dbhost_desc'] = 'Type database server IP address or host name. Use a system DSN name if using ODBC.';
$string['dbname'] = 'Database name';
$string['dbname_desc'] = 'Leave empty if using a DSN name in database host.';
$string['dbpass'] = 'Database password';
$string['dbsetupsql'] = 'Database setup command';
$string['dbsetupsql_desc'] = 'SQL command for special database setup, often used to setup communication encoding - example for MySQL and PostgreSQL: <em>SET NAMES \'utf8\'</em>';
+1 -1
View File
@@ -41,7 +41,7 @@ if ($ADMIN->fulltree) {
$settings->add(new admin_setting_configpasswordunmask('enrol_database/dbpass', get_string('dbpass', 'enrol_database'), '', ''));
$settings->add(new admin_setting_configtext('enrol_database/dbname', get_string('dbname', 'enrol_database'), '', ''));
$settings->add(new admin_setting_configtext('enrol_database/dbname', get_string('dbname', 'enrol_database'), get_string('dbname_desc', 'enrol_database'), ''));
$settings->add(new admin_setting_configtext('enrol_database/dbencoding', get_string('dbencoding', 'enrol_database'), '', 'utf-8'));
+1 -1
View File
@@ -962,7 +962,7 @@ class enrol_ldap_plugin extends enrol_plugin {
$template->groupmodeforce = $courseconfig->groupmodeforce;
$template->visible = $courseconfig->visible;
$template->lang = $courseconfig->lang;
$template->groupmodeforce = $courseconfig->groupmodeforce;
$template->enablecompletion = $courseconfig->enablecompletion;
}
$course = $template;
+6 -1
View File
@@ -46,7 +46,12 @@ class enrol_meta_plugin extends enrol_plugin {
} else if (empty($instance->name)) {
$enrol = $this->get_name();
$course = $DB->get_record('course', array('id'=>$instance->customint1));
$coursename = format_string(get_course_display_name_for_list($course));
if ($course) {
$coursename = format_string(get_course_display_name_for_list($course));
} else {
// Use course id, if course is deleted.
$coursename = $instance->customint1;
}
return get_string('pluginname', 'enrol_' . $enrol) . ' (' . $coursename . ')';
} else {
return format_string($instance->name);
+1 -1
View File
@@ -193,7 +193,7 @@ class core_enrol_renderer extends plugin_renderer_base {
if ($canassign and (is_siteadmin() or isset($assignableroles[$roleid])) and !$role['unchangeable']) {
$strunassign = get_string('unassignarole', 'role', $role['text']);
$icon = html_writer::empty_tag('img', array('alt'=>$strunassign, 'src'=>$iconenrolremove));
$url = new moodle_url($pageurl, array('action'=>'unassign', 'role'=>$roleid, 'user'=>$userid));
$url = new moodle_url($pageurl, array('action'=>'unassign', 'roleid'=>$roleid, 'user'=>$userid));
$rolesoutput .= html_writer::tag('div', $role['text'] . html_writer::link($url, $icon, array('class'=>'unassignrolelink', 'rel'=>$roleid, 'title'=>$strunassign)), array('class'=>'role role_'.$roleid));
} else {
$rolesoutput .= html_writer::tag('div', $role['text'], array('class'=>'role unchangeable', 'rel'=>$roleid));
+2 -2
View File
@@ -73,7 +73,7 @@ if ($action) {
*/
case 'unassign':
if (has_capability('moodle/role:assign', $manager->get_context())) {
$role = required_param('role', PARAM_INT);
$role = required_param('roleid', PARAM_INT);
$user = required_param('user', PARAM_INT);
if ($confirm && $manager->unassign_role_from_user($user, $role)) {
redirect($PAGE->url);
@@ -81,7 +81,7 @@ if ($action) {
$user = $DB->get_record('user', array('id'=>$user), '*', MUST_EXIST);
$allroles = $manager->get_all_roles();
$role = $allroles[$role];
$yesurl = new moodle_url($PAGE->url, array('action'=>'unassign', 'role'=>$role->id, 'user'=>$user->id, 'confirm'=>1, 'sesskey'=>sesskey()));
$yesurl = new moodle_url($PAGE->url, array('action'=>'unassign', 'roleid'=>$role->id, 'user'=>$user->id, 'confirm'=>1, 'sesskey'=>sesskey()));
$message = get_string('unassignconfirm', 'role', array('user'=>fullname($user, true), 'role'=>$role->localname));
$pagetitle = get_string('unassignarole', 'role', $role->localname);
$pagecontent = $OUTPUT->confirm($message, $yesurl, $PAGE->url);
+2 -2
View File
@@ -400,7 +400,7 @@ class core_files_renderer extends plugin_renderer_base {
<button class="{!}fp-file-cancel">'.get_string('cancel').'</button>
</div>
</form>
<div class="fp-info">
<div class="fp-info clearfix">
<div class="fp-hr"></div>
<p class="{!}fp-thumbnail"></p>
<div class="fp-fileinfo">
@@ -699,7 +699,7 @@ class core_files_renderer extends plugin_renderer_base {
<button class="{!}fp-select-cancel">'.get_string('cancel').'</button>
</div>
</form>
<div class="fp-info">
<div class="fp-info clearfix">
<div class="fp-hr"></div>
<p class="{!}fp-thumbnail"></p>
<div class="fp-fileinfo">
+18 -27
View File
@@ -895,38 +895,29 @@ function badges_add_course_navigation(navigation_node $coursenode, stdClass $cou
$coursecontext = context_course::instance($course->id);
$isfrontpage = (!$coursecontext || $course->id == $SITE->id);
$canmanage = has_any_capability(array('moodle/badges:viewawarded',
'moodle/badges:createbadge',
'moodle/badges:awardbadge',
'moodle/badges:configurecriteria',
'moodle/badges:configuremessages',
'moodle/badges:configuredetails',
'moodle/badges:deletebadge'), $coursecontext);
if (!empty($CFG->enablebadges) && !empty($CFG->badges_allowcoursebadges) && !$isfrontpage) {
if (has_capability('moodle/badges:configuredetails', $coursecontext)) {
$coursenode->add(get_string('coursebadges', 'badges'), null,
navigation_node::TYPE_CONTAINER, null, 'coursebadges',
new pix_icon('i/badge', get_string('coursebadges', 'badges')));
if (!empty($CFG->enablebadges) && !empty($CFG->badges_allowcoursebadges) && !$isfrontpage && $canmanage) {
$coursenode->add(get_string('coursebadges', 'badges'), null,
navigation_node::TYPE_CONTAINER, null, 'coursebadges',
new pix_icon('i/badge', get_string('coursebadges', 'badges')));
if (has_capability('moodle/badges:viewawarded', $coursecontext)) {
$url = new moodle_url('/badges/index.php',
array('type' => BADGE_TYPE_COURSE, 'id' => $course->id));
$url = new moodle_url('/badges/index.php', array('type' => BADGE_TYPE_COURSE, 'id' => $course->id));
$coursenode->get('coursebadges')->add(get_string('managebadges', 'badges'), $url,
navigation_node::TYPE_SETTING, null, 'coursebadges');
}
$coursenode->get('coursebadges')->add(get_string('managebadges', 'badges'), $url,
navigation_node::TYPE_SETTING, null, 'coursebadges');
if (has_capability('moodle/badges:createbadge', $coursecontext)) {
$url = new moodle_url('/badges/newbadge.php',
array('type' => BADGE_TYPE_COURSE, 'id' => $course->id));
if (has_capability('moodle/badges:createbadge', $coursecontext)) {
$url = new moodle_url('/badges/newbadge.php', array('type' => BADGE_TYPE_COURSE, 'id' => $course->id));
$coursenode->get('coursebadges')->add(get_string('newbadge', 'badges'), $url,
navigation_node::TYPE_SETTING, null, 'newbadge');
}
} else if (has_capability('moodle/badges:awardbadge', $coursecontext)) {
$coursenode->add(get_string('coursebadges', 'badges'), null,
navigation_node::TYPE_CONTAINER, null, 'coursebadges',
new pix_icon('i/badge', get_string('coursebadges', 'badges')));
$url = new moodle_url('/badges/index.php',
array('type' => BADGE_TYPE_COURSE, 'id' => $course->id));
$coursenode->get('coursebadges')->add(get_string('managebadges', 'badges'), $url,
navigation_node::TYPE_SETTING, null, 'coursebadges');
$coursenode->get('coursebadges')->add(get_string('newbadge', 'badges'), $url,
navigation_node::TYPE_SETTING, null, 'newbadge');
}
}
}
+7 -2
View File
@@ -42,6 +42,11 @@ require_once(__DIR__ . '/../../filelib.php');
*/
class behat_util extends testing_util {
/**
* The behat test site fullname and shortname.
*/
const BEHATSITENAME = "Acceptance test site";
/**
* @var array Files to skip when resetting dataroot folder
*/
@@ -70,8 +75,8 @@ class behat_util extends testing_util {
$options = array();
$options['adminuser'] = 'admin';
$options['adminpass'] = 'admin';
$options['fullname'] = 'Acceptance test site';
$options['shortname'] = 'Acceptance test site';
$options['fullname'] = self::BEHATSITENAME;
$options['shortname'] = self::BEHATSITENAME;
install_cli_database($options, false);
+2 -3
View File
@@ -2137,12 +2137,11 @@ class course_in_list implements IteratorAggregate {
public function has_course_overviewfiles() {
global $CFG;
if (empty($CFG->courseoverviewfileslimit)) {
return 0;
return false;
}
require_once($CFG->libdir. '/filestorage/file_storage.php');
$fs = get_file_storage();
$context = context_course::instance($this->id);
return $fs->is_area_empty($context->id, 'course', 'overviewfiles');
return !$fs->is_area_empty($context->id, 'course', 'overviewfiles');
}
/**
+33 -2
View File
@@ -261,10 +261,10 @@ abstract class moodleform {
$submission = array();
if ($method == 'post') {
if (!empty($_POST)) {
$submission = $_POST;
$submission = $this->_get_post_params();
}
} else {
$submission = array_merge_recursive($_GET, $_POST); // emulate handling of parameters in xxxx_param()
$submission = array_merge_recursive($_GET, $this->_get_post_params()); // Emulate handling of parameters in xxxx_param().
}
// following trick is needed to enable proper sesskey checks when using GET forms
@@ -283,6 +283,37 @@ abstract class moodleform {
$this->_form->updateSubmission($submission, $files);
}
/**
* Internal method. Gets all POST variables, bypassing max_input_vars limit if needed.
*
* @return array All POST variables as an array, in the same format as $_POST.
*/
protected function _get_post_params() {
$enctype = $this->_form->getAttribute('enctype');
$max = (int)ini_get('max_input_vars');
if (empty($max) || count($_POST, COUNT_RECURSIVE) < $max || (!empty($enctype) && $enctype == 'multipart/form-data')) {
return $_POST;
}
// Large POST request with enctype supported by php://input.
// Parse php://input in chunks to bypass max_input_vars limit, which also applies to parse_str().
$allvalues = array();
$values = array();
$str = file_get_contents("php://input");
$delim = '&';
$fun = create_function('$p', 'return implode("'.$delim.'", $p);');
$chunks = array_map($fun, array_chunk(explode($delim, $str), $max));
foreach ($chunks as $chunk) {
parse_str($chunk, $values);
$allvalues = array_merge_recursive($allvalues, $values);
}
return $allvalues;
}
/**
* Internal method. Validates all old-style deprecated uploaded files.
* The new way is to upload files via repository api.
+1 -3
View File
@@ -228,9 +228,7 @@ class oauth_helper {
// oauth_token_secret
$result = $this->parse_result($content);
if (empty($result['oauth_token'])) {
// failed
var_dump($result);
exit;
throw new moodle_exception('Error while requesting an oauth token');
}
// build oauth authrize url
if (!empty($this->oauth_callback)) {
+47 -28
View File
@@ -34,6 +34,8 @@ use Behat\Behat\Event\SuiteEvent as SuiteEvent,
Behat\Behat\Event\StepEvent as StepEvent,
WebDriver\Exception\NoSuchWindow as NoSuchWindow,
WebDriver\Exception\UnexpectedAlertOpen as UnexpectedAlertOpen,
WebDriver\Exception\UnknownError as UnknownError,
WebDriver\Exception\CurlExec as CurlExec,
WebDriver\Exception\NoAlertOpenError as NoAlertOpenError;
/**
@@ -103,7 +105,9 @@ class behat_hooks extends behat_base {
}
if (!behat_util::is_server_running()) {
throw new Exception($CFG->behat_wwwroot . ' is not available, ensure you started your PHP built-in server. More info in ' . behat_command::DOCS_URL . '#Running_tests');
throw new Exception($CFG->behat_wwwroot .
' is not available, ensure you started your PHP built-in server or your web server is correctly started and set up.' .
' More info in ' . behat_command::DOCS_URL . '#Running_tests');
}
// Prevents using outdated data, upgrade script would start and tests would fail.
@@ -139,9 +143,23 @@ class behat_hooks extends behat_base {
throw new coding_exception('Behat only can modify the test database and the test dataroot!');
}
try {
$session = $this->getSession();
} catch (CurlExec $e) {
// Exception thrown by WebDriver, so only @javascript tests will be caugth; in
// behat_util::is_server_running() we already checked that the server is running.
$moreinfo = 'More info in ' . behat_command::DOCS_URL . '#Running_tests';
$msg = 'Selenium server is not running, you need to start it to run tests that involve Javascript. ' . $moreinfo;
throw new Exception($msg);
} catch (UnknownError $e) {
// Generic 'I have no idea' Selenium error. Custom exception to provide more feedback about possible solutions.
$this->throw_unknown_exception($e);
}
// We need the Mink session to do it and we do it only before the first scenario.
if (self::is_first_scenario()) {
behat_selectors::register_moodle_selectors($this->getSession());
behat_selectors::register_moodle_selectors($session);
}
// Avoid some notices / warnings.
@@ -164,19 +182,25 @@ class behat_hooks extends behat_base {
if (!empty($CFG->behat_restart_browser_after) && $this->running_javascript()) {
$now = time();
if (self::$lastbrowsersessionstart + $CFG->behat_restart_browser_after < $now) {
$this->getSession()->restart();
$session->restart();
self::$lastbrowsersessionstart = $now;
}
}
// Start always in the the homepage.
$this->getSession()->visit($this->locate_path('/'));
try {
// Let's be conservative as we never know when new upstream issues will affect us.
$session->visit($this->locate_path('/'));
} catch (UnknownError $e) {
$this->throw_unknown_exception($e);
}
// Checking that the root path is a Moodle test site.
if (self::is_first_scenario()) {
$notestsiteexception = new Exception('The base URL (' . $CFG->wwwroot . ') is not a behat test site, ' .
'ensure you started the built-in web server in the correct directory');
$this->find("xpath", "//head/child::title[normalize-space(.)='Acceptance test site']", $notestsiteexception);
'ensure you started the built-in web server in the correct directory or your web server is correctly started and set up');
$this->find("xpath", "//head/child::title[normalize-space(.)='" . behat_util::BEHATSITENAME . "']", $notestsiteexception);
self::$initprocessesfinished = true;
}
@@ -184,7 +208,7 @@ class behat_hooks extends behat_base {
// Closing JS dialogs if present. Otherwise they would block this scenario execution.
if ($this->running_javascript()) {
try {
$this->getSession()->getDriver()->getWebDriverSession()->accept_alert();
$session->getDriver()->getWebDriverSession()->accept_alert();
} catch (NoAlertOpenError $e) {
// All ok, there should not be JS dialogs in theory.
}
@@ -192,27 +216,6 @@ class behat_hooks extends behat_base {
}
/**
* Ensures selenium is running.
*
* Is only executed in scenarios which requires Javascript to run,
* it returns a direct error message about what's going on.
*
* @throws Exception
* @BeforeScenario @javascript
*/
public function before_scenario_javascript($event) {
// Just trying if server responds.
try {
$this->getSession()->wait(0, false);
} catch (Exception $e) {
$moreinfo = 'More info in ' . behat_command::DOCS_URL . '#Running_tests';
$msg = 'Selenium server is not running, you need to start it to run tests that involves Javascript. ' . $moreinfo;
throw new Exception($msg);
}
}
/**
* Checks that all DOM is ready.
*
@@ -246,6 +249,9 @@ class behat_hooks extends behat_base {
} catch (NoSuchWindow $e) {
// If we were interacting with a popup window it will not exists after closing it.
} catch (UnknownError $e) {
// Custom exception to provide more feedback about possible solutions.
$this->throw_unknown_exception($e);
}
}
@@ -363,4 +369,17 @@ class behat_hooks extends behat_base {
protected static function is_first_scenario() {
return !(self::$initprocessesfinished);
}
/**
* Throws an exception after appending an extra info text.
*
* @throws Exception
* @param UnknownError $exception
* @return void
*/
protected function throw_unknown_exception(UnknownError $exception) {
$text = get_string('unknownexceptioninfo', 'tool_behat');
throw new Exception($text . PHP_EOL . $exception->getMessage());
}
}
+113 -1
View File
@@ -532,4 +532,116 @@ class coursecatlib_testcase extends advanced_testcase {
$CFG->coursecontact = $oldcoursecontact;
}
}
public function test_overview_files() {
global $CFG;
$this->setAdminUser();
$cat1 = coursecat::create(array('name' => 'Cat1'));
// Create course c1 with one image file.
$dratid1 = $this->fill_draft_area(array('filename.jpg' => 'Test file contents1'));
$c1 = $this->getDataGenerator()->create_course(array('category' => $cat1->id,
'fullname' => 'Test 1', 'overviewfiles_filemanager' => $dratid1));
// Create course c2 with two image files (only one file will be added because of settings).
$dratid2 = $this->fill_draft_area(array('filename21.jpg' => 'Test file contents21', 'filename22.jpg' => 'Test file contents22'));
$c2 = $this->getDataGenerator()->create_course(array('category' => $cat1->id,
'fullname' => 'Test 2', 'overviewfiles_filemanager' => $dratid2));
// Create course c3 without files.
$c3 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 3'));
// Change the settings to allow multiple files of any types.
$CFG->courseoverviewfileslimit = 3;
$CFG->courseoverviewfilesext = '*';
// Create course c5 with two image files.
$dratid4 = $this->fill_draft_area(array('filename41.jpg' => 'Test file contents41', 'filename42.jpg' => 'Test file contents42'));
$c4 = $this->getDataGenerator()->create_course(array('category' => $cat1->id,
'fullname' => 'Test 4', 'overviewfiles_filemanager' => $dratid4));
// Create course c6 with non-image file.
$dratid5 = $this->fill_draft_area(array('filename51.zip' => 'Test file contents51'));
$c5 = $this->getDataGenerator()->create_course(array('category' => $cat1->id,
'fullname' => 'Test 5', 'overviewfiles_filemanager' => $dratid5));
// Reset default settings.
$CFG->courseoverviewfileslimit = 1;
$CFG->courseoverviewfilesext = '.jpg,.gif,.png';
$courses = $cat1->get_courses();
$this->assertTrue($courses[$c1->id]->has_course_overviewfiles());
$this->assertTrue($courses[$c2->id]->has_course_overviewfiles());
$this->assertFalse($courses[$c3->id]->has_course_overviewfiles());
$this->assertTrue($courses[$c4->id]->has_course_overviewfiles());
$this->assertTrue($courses[$c5->id]->has_course_overviewfiles()); // Does not validate the filetypes.
$this->assertEquals(1, count($courses[$c1->id]->get_course_overviewfiles()));
$this->assertEquals(1, count($courses[$c2->id]->get_course_overviewfiles()));
$this->assertEquals(0, count($courses[$c3->id]->get_course_overviewfiles()));
$this->assertEquals(1, count($courses[$c4->id]->get_course_overviewfiles()));
$this->assertEquals(0, count($courses[$c5->id]->get_course_overviewfiles())); // Validate the filetypes.
// Overview files are not allowed, all functions return empty values.
$CFG->courseoverviewfileslimit = 0;
$this->assertFalse($courses[$c1->id]->has_course_overviewfiles());
$this->assertFalse($courses[$c2->id]->has_course_overviewfiles());
$this->assertFalse($courses[$c3->id]->has_course_overviewfiles());
$this->assertFalse($courses[$c4->id]->has_course_overviewfiles());
$this->assertFalse($courses[$c5->id]->has_course_overviewfiles());
$this->assertEquals(0, count($courses[$c1->id]->get_course_overviewfiles()));
$this->assertEquals(0, count($courses[$c2->id]->get_course_overviewfiles()));
$this->assertEquals(0, count($courses[$c3->id]->get_course_overviewfiles()));
$this->assertEquals(0, count($courses[$c4->id]->get_course_overviewfiles()));
$this->assertEquals(0, count($courses[$c5->id]->get_course_overviewfiles()));
// Multiple overview files are allowed but still limited to images.
$CFG->courseoverviewfileslimit = 3;
$this->assertTrue($courses[$c1->id]->has_course_overviewfiles());
$this->assertTrue($courses[$c2->id]->has_course_overviewfiles());
$this->assertFalse($courses[$c3->id]->has_course_overviewfiles());
$this->assertTrue($courses[$c4->id]->has_course_overviewfiles());
$this->assertTrue($courses[$c5->id]->has_course_overviewfiles()); // Still does not validate the filetypes.
$this->assertEquals(1, count($courses[$c1->id]->get_course_overviewfiles()));
$this->assertEquals(1, count($courses[$c2->id]->get_course_overviewfiles())); // Only 1 file was actually added.
$this->assertEquals(0, count($courses[$c3->id]->get_course_overviewfiles()));
$this->assertEquals(2, count($courses[$c4->id]->get_course_overviewfiles()));
$this->assertEquals(0, count($courses[$c5->id]->get_course_overviewfiles()));
// Multiple overview files of any type are allowed.
$CFG->courseoverviewfilesext = '*';
$this->assertTrue($courses[$c1->id]->has_course_overviewfiles());
$this->assertTrue($courses[$c2->id]->has_course_overviewfiles());
$this->assertFalse($courses[$c3->id]->has_course_overviewfiles());
$this->assertTrue($courses[$c4->id]->has_course_overviewfiles());
$this->assertTrue($courses[$c5->id]->has_course_overviewfiles());
$this->assertEquals(1, count($courses[$c1->id]->get_course_overviewfiles()));
$this->assertEquals(1, count($courses[$c2->id]->get_course_overviewfiles()));
$this->assertEquals(0, count($courses[$c3->id]->get_course_overviewfiles()));
$this->assertEquals(2, count($courses[$c4->id]->get_course_overviewfiles()));
$this->assertEquals(1, count($courses[$c5->id]->get_course_overviewfiles()));
}
/**
* Creates a draft area for current user and fills it with fake files
*
* @param array $files array of files that need to be added to filearea, filename => filecontents
* @return int draftid for the filearea
*/
protected function fill_draft_area(array $files) {
global $USER;
$usercontext = context_user::instance($USER->id);
$draftid = file_get_unused_draft_itemid();
foreach ($files as $filename => $filecontents) {
// Add actual file there.
$filerecord = array('component' => 'user', 'filearea' => 'draft',
'contextid' => $usercontext->id, 'itemid' => $draftid,
'filename' => $filename, 'filepath' => '/');
$fs = get_file_storage();
$fs->create_file_from_string($filerecord, $filecontents);
}
return $draftid;
}
}
+40 -9
View File
@@ -2650,11 +2650,13 @@ class assign {
if ($teamsubmission) {
$showsubmit = $showedit &&
$teamsubmission &&
($teamsubmission->status == ASSIGN_SUBMISSION_STATUS_DRAFT);
($teamsubmission->status != ASSIGN_SUBMISSION_STATUS_SUBMITTED) &&
!$this->submission_empty($teamsubmission);
} else {
$showsubmit = $showedit &&
$submission &&
($submission->status == ASSIGN_SUBMISSION_STATUS_DRAFT);
($submission->status != ASSIGN_SUBMISSION_STATUS_SUBMITTED) &&
!$this->submission_empty($submission);
}
if (!$this->get_instance()->submissiondrafts) {
$showsubmit = false;
@@ -3308,11 +3310,17 @@ class assign {
}
}
$showsubmit = ($submission || $teamsubmission) && $showlinks;
if ($teamsubmission && ($teamsubmission->status != ASSIGN_SUBMISSION_STATUS_DRAFT)) {
$showsubmit = ($submission || $teamsubmission) && $showlinks && $this->submissions_open($user->id);
if ($teamsubmission && ($teamsubmission->status == ASSIGN_SUBMISSION_STATUS_SUBMITTED)) {
$showsubmit = false;
}
if ($submission && ($submission->status != ASSIGN_SUBMISSION_STATUS_DRAFT)) {
if ($teamsubmission && $this->submission_empty($teamsubmission)) {
$showsubmit = false;
}
if ($submission && ($submission->status == ASSIGN_SUBMISSION_STATUS_SUBMITTED)) {
$showsubmit = false;
}
if ($submission && $this->submission_empty($submission)) {
$showsubmit = false;
}
if (!$this->get_instance()->submissiondrafts) {
@@ -4209,6 +4217,9 @@ class assign {
require_once($CFG->dirroot . '/mod/assign/submissionconfirmform.php');
require_sesskey();
if (!$this->submissions_open()) {
return $this->view_student_error_message();
}
$instance = $this->get_instance();
$data = new stdClass();
$adminconfig = $this->get_admin_config();
@@ -4745,6 +4756,25 @@ class assign {
return true;
}
/**
* Determine if the current submission is empty or not.
*
* @param submission $submission the students submission record to check.
* @return bool
*/
public function submission_empty($submission) {
$allempty = true;
foreach ($this->submissionplugins as $plugin) {
if ($plugin->is_enabled() && $plugin->is_visible()) {
if (!$allempty || !$plugin->is_empty($submission)) {
$allempty = false;
}
}
}
return $allempty;
}
/**
* Save assignment submission.
*
@@ -4762,6 +4792,10 @@ class assign {
// Need submit permission to submit an assignment.
require_capability('mod/assign:submit', $this->context);
require_sesskey();
if (!$this->submissions_open()) {
$notices[] = get_string('duedatereached', 'assign');
return false;
}
$instance = $this->get_instance();
$data = new stdClass();
@@ -4789,7 +4823,6 @@ class assign {
return true;
}
$allempty = true;
$pluginerror = false;
foreach ($this->submissionplugins as $plugin) {
if ($plugin->is_enabled() && $plugin->is_visible()) {
@@ -4797,11 +4830,9 @@ class assign {
$notices[] = $plugin->get_error();
$pluginerror = true;
}
if (!$allempty || !$plugin->is_empty($submission)) {
$allempty = false;
}
}
}
$allempty = $this->submission_empty($submission);
if ($pluginerror || $allempty) {
if ($allempty) {
$notices[] = get_string('submissionempty', 'mod_assign');
+80
View File
@@ -292,6 +292,43 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
$this->assertEquals($now, $instance->duedate);
}
public function test_cannot_submit_empty() {
global $PAGE;
$this->setUser($this->editingteachers[0]);
$assign = $this->create_instance(array('submissiondrafts'=>1));
$PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
// Test you cannot see the submit button for an offline assignment regardless.
$this->setUser($this->students[0]);
$output = $assign->view_student_summary($this->students[0], true);
$this->assertNotContains(get_string('submitassignment', 'assign'), $output, 'Can submit empty offline assignment');
// Test you cannot see the submit button for an online text assignment with no submission.
$this->setUser($this->editingteachers[0]);
$instance = $assign->get_instance();
$instance->instance = $instance->id;
$instance->assignsubmission_onlinetext_enabled = 1;
$assign->update_instance($instance);
$this->setUser($this->students[0]);
$output = $assign->view_student_summary($this->students[0], true);
$this->assertNotContains(get_string('submitassignment', 'assign'), $output, 'Cannot submit empty onlinetext assignment');
// Simulate a submission.
$submission = $assign->get_user_submission($this->students[0]->id, true);
$data = new stdClass();
$data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
'text'=>'Submission text',
'format'=>FORMAT_MOODLE);
$plugin = $assign->get_submission_plugin_by_type('onlinetext');
$plugin->save($submission, $data);
// Test you can see the submit button for an online text assignment with a submission.
$output = $assign->view_student_summary($this->students[0], true);
$this->assertContains(get_string('submitassignment', 'assign'), $output, 'Can submit non empty onlinetext assignment');
}
public function test_list_participants() {
$this->create_extra_users();
$this->setUser($this->editingteachers[0]);
@@ -740,5 +777,48 @@ class mod_assign_locallib_testcase extends mod_assign_base_testcase {
$grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
$this->assertEquals(50, (int)$grades[$this->students[0]->id]->rawgrade);
}
public function test_disable_submit_after_cutoff_date() {
global $PAGE;
$this->setUser($this->editingteachers[0]);
$now = time();
$tomorrow = $now + 24*60*60;
$lastweek = $now - 7*24*60*60;
$yesterday = $now - 24*60*60;
$assign = $this->create_instance(array('duedate'=>$yesterday,
'cutoffdate'=>$tomorrow,
'assignsubmission_onlinetext_enabled'=>1));
$PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
// Student should be able to see an add submission button.
$this->setUser($this->students[0]);
$output = $assign->view_student_summary($this->students[0], true);
$this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
// Add a submission but don't submit now.
$submission = $assign->get_user_submission($this->students[0]->id, true);
$data = new stdClass();
$data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
'text'=>'Submission text',
'format'=>FORMAT_MOODLE);
$plugin = $assign->get_submission_plugin_by_type('onlinetext');
$plugin->save($submission, $data);
// Create another instance with cut-off and due-date already passed.
$this->setUser($this->editingteachers[0]);
$now = time();
$assign = $this->create_instance(array('duedate'=>$lastweek,
'cutoffdate'=>$yesterday,
'assignsubmission_onlinetext_enabled'=>1));
$this->setUser($this->students[0]);
$output = $assign->view_student_summary($this->students[0], true);
$this->assertNotContains($output, get_string('editsubmission', 'assign'),
'Should not be able to edit after cutoff date.');
$this->assertNotContains($output, get_string('submitassignment', 'assign'),
'Should not be able to submit after cutoff date.');
}
}
+1 -1
View File
@@ -191,7 +191,7 @@ if (!$book->customtitles) {
}
}
$chaptertext = file_rewrite_pluginfile_urls($chapter->content, 'pluginfile.php', $context->id, 'mod_book', 'chapter', $chapter->id);
echo format_text($chaptertext, $chapter->contentformat, array('noclean'=>true, 'context'=>$context));
echo format_text($chaptertext, $chapter->contentformat, array('noclean'=>true, 'overflowdiv'=>true, 'context'=>$context));
echo $OUTPUT->box_end();
+5 -45
View File
@@ -3471,9 +3471,10 @@ function forum_print_post($post, $discussion, $forum, &$cm, $course, $ownpost=fa
$options->trusted = $post->messagetrust;
$options->context = $modcontext;
if ($shortenpost) {
// Prepare shortened version
// Prepare shortened version by filtering the text then shortening it.
$postclass = 'shortenedpost';
$postcontent = format_text(forum_shorten_post($post->message), $post->messageformat, $options, $course->id);
$postcontent = format_text($post->message, $post->messageformat, $options);
$postcontent = forum_shorten_post($postcontent);
$postcontent .= html_writer::link($discussionlink, get_string('readtherest', 'forum'));
$postcontent .= html_writer::tag('div', '('.get_string('numwords', 'moodle', count_words($post->message)).')',
array('class'=>'post-word-count'));
@@ -3817,50 +3818,9 @@ function forum_print_discussion_header(&$post, $forum, $group=-1, $datestring=""
* @return string
*/
function forum_shorten_post($message) {
global $CFG;
global $CFG;
$i = 0;
$tag = false;
$length = strlen($message);
$count = 0;
$stopzone = false;
$truncate = 0;
for ($i=0; $i<$length; $i++) {
$char = $message[$i];
switch ($char) {
case "<":
$tag = true;
break;
case ">":
$tag = false;
break;
default:
if (!$tag) {
if ($stopzone) {
if ($char == ".") {
$truncate = $i+1;
break 2;
}
}
$count++;
}
break;
}
if (!$stopzone) {
if ($count > $CFG->forum_shortpost) {
$stopzone = true;
}
}
}
if (!$truncate) {
$truncate = $i;
}
return substr($message, 0, $truncate);
return shorten_text($message, $CFG->forum_shortpost);
}
/**
@@ -33,6 +33,11 @@ require_once($CFG->dirroot . '/mod/resource/backup/moodle2/backup_resource_steps
*/
class backup_resource_activity_task extends backup_activity_task {
/**
* @param bool $resourceoldexists True if there are records in the resource_old table.
*/
protected static $resourceoldexists = null;
/**
* No specific settings for this activity
*/
@@ -53,18 +58,70 @@ class backup_resource_activity_task extends backup_activity_task {
* @return string the content with the URLs encoded
*/
static public function encode_content_links($content) {
global $CFG;
global $CFG, $DB;
$base = preg_quote($CFG->wwwroot,"/");
// Link to the list of resources
// Link to the list of resources.
$search="/(".$base."\/mod\/resource\/index.php\?id\=)([0-9]+)/";
$content= preg_replace($search, '$@RESOURCEINDEX*$2@$', $content);
// Link to resource view by moduleid
$search="/(".$base."\/mod\/resource\/view.php\?id\=)([0-9]+)/";
$content= preg_replace($search, '$@RESOURCEVIEWBYID*$2@$', $content);
// Link to resource view by moduleid.
$search = "/(".$base."\/mod\/resource\/view.php\?id\=)([0-9]+)/";
// Link to resource view by recordid
$search2 = "/(".$base."\/mod\/resource\/view.php\?r\=)([0-9]+)/";
// Check whether there are contents in the resource old table.
if (static::$resourceoldexists === null) {
static::$resourceoldexists = $DB->record_exists('resource_old', array());
}
// If there are links to items in the resource_old table, rewrite them to be links to the correct URL
// for their new module.
if (static::$resourceoldexists) {
// Match all of the resources.
$result = preg_match_all($search, $content, $matches, PREG_PATTERN_ORDER);
// Course module ID resource links.
if ($result) {
list($insql, $params) = $DB->get_in_or_equal($matches[2]);
$oldrecs = $DB->get_records_select('resource_old', "cmid $insql", $params, '', 'cmid, newmodule');
for ($i = 0; $i < count($matches[0]); $i++) {
$cmid = $matches[2][$i];
if (isset($oldrecs[$cmid])) {
// Resource_old item, rewrite it
$replace = '$@' . strtoupper($oldrecs[$cmid]->newmodule) . 'VIEWBYID*' . $cmid . '@$';
} else {
// Not in the resource old table, don't rewrite
$replace = '$@RESOURCEVIEWBYID*'.$cmid.'@$';
}
$content = str_replace($matches[0][$i], $replace, $content);
}
}
$matches = null;
$result = preg_match_all($search2, $content, $matches, PREG_PATTERN_ORDER);
// No resource links.
if (!$result) {
return $content;
}
// Resource ID links.
list($insql, $params) = $DB->get_in_or_equal($matches[2]);
$oldrecs = $DB->get_records_select('resource_old', "oldid $insql", $params, '', 'oldid, cmid, newmodule');
for ($i = 0; $i < count($matches[0]); $i++) {
$recordid = $matches[2][$i];
if (isset($oldrecs[$recordid])) {
// Resource_old item, rewrite it
$replace = '$@' . strtoupper($oldrecs[$recordid]->newmodule) . 'VIEWBYID*' . $oldrecs[$recordid]->cmid . '@$';
$content = str_replace($matches[0][$i], $replace, $content);
}
}
} else {
$content = preg_replace($search, '$@RESOURCEVIEWBYID*$2@$', $content);
}
return $content;
}
}
+1
View File
@@ -40,4 +40,5 @@
.path-mod-scorm.jsenabled .scorm-center { display:block;}
.path-mod-scorm.jsenabled .toc { display:block;}
.path-mod-scorm.jsenabled #scormpage #tocbox { display:block;}
#page-mod-scorm-userreport table .c2 { word-wrap:break-word; word-break: break-all;}
+1 -1
View File
@@ -108,7 +108,7 @@ Thanks very much.';
$string['collesaname'] = 'COLLES (Actual)';
$string['collesapintro'] = 'The purpose of this questionnaire is to help us understand how well the online delivery of this unit enabled you to learn.
Each one of the 24 statements below asks you to compare your <b>preferred</b> (ideal) and <b>actual</b> experience in this unit.
Each couple of the 24 statements below asks you to compare your <b>preferred</b> (ideal) and <b>actual</b> experience in this unit.
There are no \'right\' or \'wrong\' answers; we are interested only in your opinion. Please be assured that your responses will be treated with a high degree of confidentiality, and will not affect your assessment.
+23 -17
View File
@@ -509,8 +509,22 @@ function survey_print_multi($question) {
$options = explode( ",", $question->options);
$numoptions = count($options);
// COLLES Actual (which is having questions of type 1) and COLLES Preferred (type 2)
// expect just one answer per question. COLLES Actual and Preferred (type 3) expects
// two answers per question. ATTLS (having a single question of type 1) expects one
// answer per question. CIQ is not using multiquestions (i.e. a question with subquestions).
// Note that the type of subquestions does not really matter, it's the type of the
// question itself that determines everything.
$oneanswer = ($question->type == 1 || $question->type == 2) ? true : false;
// COLLES Preferred (having questions of type 2) will use the radio elements with the name
// like qP1, qP2 etc. COLLES Actual and ATTLS have radios like q1, q2 etc.
if ($question->type == 2) {
$P = "P";
} else {
$P = "";
}
echo "<tr class=\"smalltext\"><th scope=\"row\">$strresponses</th>";
echo "<th scope=\"col\" class=\"hresponse\">". get_string('notyetanswered', 'survey'). "</th>";
while (list ($key, $val) = each ($options)) {
@@ -518,28 +532,21 @@ function survey_print_multi($question) {
}
echo "</tr>\n";
if ($oneanswer) {
echo "<tr><th scope=\"col\" colspan=\"7\">$question->intro</th></tr>\n";
} else {
echo "<tr><th scope=\"col\" colspan=\"7\">$question->intro</th></tr>\n";
}
echo "<tr><th scope=\"col\" colspan=\"7\">$question->intro</th></tr>\n";
$subquestions = $DB->get_records_list("survey_questions", "id", explode(',', $question->multi));
foreach ($subquestions as $q) {
$qnum++;
$rowclass = survey_question_rowclass($qnum);
if ($oneanswer) {
$rowclass = survey_question_rowclass($qnum);
} else {
$rowclass = survey_question_rowclass(round($qnum / 2));
}
if ($q->text) {
$q->text = get_string($q->text, "survey");
}
$oneanswer = ($q->type == 1 || $q->type == 2) ? true : false;
if ($q->type == 2) {
$P = "P";
} else {
$P = "";
}
echo "<tr class=\"$rowclass rblock\">";
if ($oneanswer) {
echo "<th scope=\"row\" class=\"optioncell\">";
@@ -557,15 +564,14 @@ function survey_print_multi($question) {
$checklist["q$P$q->id"] = 0;
} else {
// yu : fix for MDL-7501, possibly need to use user flag as this is quite ugly.
echo "<th scope=\"row\" class=\"optioncell\">";
echo "<b class=\"qnumtopcell\">$qnum</b> &nbsp; ";
$qnum++;
echo "<span class=\"preferthat smalltext\">$stripreferthat</span> &nbsp; ";
echo "<span class=\"preferthat\">$stripreferthat</span> &nbsp; ";
echo "<span class=\"option\">$q->text</span></th>\n";
$default = get_accesshide($strdefault);
echo '<td class="whitecell"><label for="qP'. $P.$q->id .'"><input type="radio" name="qP'.$P.$q->id. '" id="qP'. $q->id .'" value="0" checked="checked" />'.$default.'</label></td>';
echo '<td class="whitecell"><label for="qP'.$q->id.'"><input type="radio" name="qP'.$q->id.'" id="qP'.$q->id.'" value="0" checked="checked" />'.$default.'</label></td>';
for ($i=1;$i<=$numoptions;$i++) {
@@ -578,7 +584,7 @@ function survey_print_multi($question) {
echo "<tr class=\"$rowclass rblock\">";
echo "<th scope=\"row\" class=\"optioncell\">";
echo "<b class=\"qnumtopcell\">$qnum</b> &nbsp; ";
echo "<span class=\"foundthat smalltext\">$strifoundthat</span> &nbsp; ";
echo "<span class=\"foundthat\">$strifoundthat</span> &nbsp; ";
echo "<span class=\"option\">$q->text</span></th>\n";
$default = get_accesshide($strdefault);
@@ -56,8 +56,12 @@ class qformat_blackboard_six_pool_test extends question_testcase {
$q = $questions[5];
// If qtype_ddmatch is installed, the formatter produces ddmatch
// qtypes, not match ones.
$ddmatchisinstalled = question_bank::is_qtype_installed('ddmatch');
$expectedq = new stdClass();
$expectedq->qtype = 'match';
$expectedq->qtype = $ddmatchisinstalled ? 'ddmatch' : 'match';
$expectedq->name = 'Classify the animals.';
$expectedq->questiontext = '<i>Classify the animals.</i>';
$expectedq->questiontextformat = FORMAT_HTML;
@@ -78,8 +82,17 @@ class qformat_blackboard_six_pool_test extends question_testcase {
array('text' => '', 'format' => FORMAT_HTML),
array('text' => 'frog', 'format' => FORMAT_HTML),
array('text' => 'newt', 'format' => FORMAT_HTML));
$expectedq->subanswers = array('mammal', 'insect', 'amphibian', 'amphibian');
if ($ddmatchisinstalled) {
$expectedq->subanswers = array(
array('text' => 'mammal', 'format' => FORMAT_HTML),
array('text' => 'insect', 'format' => FORMAT_HTML),
array('text' => 'amphibian', 'format' => FORMAT_HTML),
array('text' => 'amphibian', 'format' => FORMAT_HTML),
);
} else {
$expectedq->subanswers = array('mammal', 'insect', 'amphibian', 'amphibian');
}
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
@@ -53,8 +53,12 @@ class qformat_blackboard_six_qti_test extends question_testcase {
$questions = $importer->readquestions($xml);
$q = $questions[4];
// If qtype_ddmatch is installed, the formatter produces ddmatch
// qtypes, not match ones.
$ddmatchisinstalled = question_bank::is_qtype_installed('ddmatch');
$expectedq = new stdClass();
$expectedq->qtype = 'match';
$expectedq->qtype = $ddmatchisinstalled ? 'ddmatch' : 'match';
$expectedq->name = 'Classify the animals.';
$expectedq->questiontext = 'Classify the animals.';
$expectedq->questiontextformat = FORMAT_HTML;
@@ -75,7 +79,16 @@ class qformat_blackboard_six_qti_test extends question_testcase {
array('text' => 'cat', 'format' => FORMAT_HTML),
array('text' => 'frog', 'format' => FORMAT_HTML),
array('text' => 'newt', 'format' => FORMAT_HTML));
$expectedq->subanswers = array('insect', 'mammal', 'amphibian', 'amphibian');
if ($ddmatchisinstalled) {
$expectedq->subanswers = array(
array('text' => 'insect', 'format' => FORMAT_HTML),
array('text' => 'mammal', 'format' => FORMAT_HTML),
array('text' => 'amphibian', 'format' => FORMAT_HTML),
array('text' => 'amphibian', 'format' => FORMAT_HTML),
);
} else {
$expectedq->subanswers = array('insect', 'mammal', 'amphibian', 'amphibian');
}
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
@@ -30,3 +30,4 @@ $string['url'] = 'URL';
$string['url:view'] = 'Use URL downloader in file picker';
$string['validname'] = 'You must provide a valid file name';
$string['configplugin'] = 'URL repository type configuration';
$string['validfiletype'] = 'You must provide a URL to an image file or a page containing images.';
+2
View File
@@ -168,6 +168,8 @@ EOD;
} else if (strstr($info['content_type'], 'image/')) {
// download this file
$this->add_image_to_list($info['url'], $info['url'], $list);
} else {
$list['error'] = get_string('validfiletype', 'repository_url');
}
// parse all found css styles
@@ -119,6 +119,9 @@
#searchform_search {
width: auto;
}
.block_rss_client .list li {
border-top-color: darken(@wellBackground, 7%);
}
// Overide for RTL layout.
.dir-rtl {
@@ -174,3 +174,12 @@ img.icon-pre {
.opacity(100);
display: inline;
}
// Extends bootstrapbase/less/bootstrap/navbar.less
// to enable scroll in longer menus especially language menu.
.open > .dropdown-menu {
display: block;
max-height: 500px;
overflow-y: auto;
}
File diff suppressed because one or more lines are too long
+1 -2
View File
@@ -35,8 +35,7 @@ body {
.errorbox,
.continuebutton,
.singlebutton,
.buttons,
.singleselect {
.buttons {
text-align: center;
margin: 1em 0;
}
+2 -7
View File
@@ -236,14 +236,9 @@ form.loginform #rememberusername {
margin-right:0;
}
/* RSS - MDL-29367 */
.block_rss_client .list li:first-child {
border-top-width: 0;
}
/* RSS - MDL-28561 */
.block_rss_client .list li {
border-top: 1px solid #DDDDDD;
padding: 5px;
border-top-color: #DDD;
}
/* Upcoming events - MDL-29367 */
+1 -2
View File
@@ -77,8 +77,7 @@
/** RSS Client **/
.block_rss_client .image {text-align:center;}
.block_rss_client .list li {padding:5px;font-size:0.85em;border-top:1px solid #DDD;}
.block_rss_client .list li:first-child {border-top-width: 0px;}
.block_rss_client .list li {font-size:0.85em;border-top-color:#DDD;}
.block_rss_client .list li .description {color:#555555;font-size:0.8em;padding-left:1em;}
/** Site main menu **/
+2 -2
View File
@@ -29,11 +29,11 @@
defined('MOODLE_INTERNAL') || die();
$version = 2013051402.00; // 20130514 = branching date YYYYMMDD - do not modify!
$version = 2013051402.01; // 20130514 = branching date YYYYMMDD - do not modify!
// RR = release increments - 00 in DEV branches
// .XX = incremental changes
$release = '2.5.2 (Build: 20130909)'; // Human-friendly version name
$release = '2.5.2+ (Build: 20130913)'; // Human-friendly version name
$branch = '25'; // this version's branch
$maturity = MATURITY_STABLE; // this version's maturity level