ob_start(); //for whitespace test
require('../../../config.php');
-
- // extra whitespace test - intentionally breaks cookieless mode
- $extraws = '';
- while (ob_get_level()) {
- $extraws .= ob_get_contents();
- ob_end_clean();
- }
+ $extraws = ob_get_clean();
require_once($CFG->libdir.'/adminlib.php');
html_writer::link(new moodle_url('/course/view.php',
array('id' => $quizinfo->courseid)), format_string($quizinfo->shortname)),
html_writer::link(new moodle_url('/mod/quiz/view.php',
- array('id' => $quizinfo->name)), format_string($quizinfo->name)),
+ array('q' => $quizinfo->id)), format_string($quizinfo->name)),
$quizinfo->attemptcount,
$quizinfo->questionattempts ? $quizinfo->questionattempts : 0,
);
$mform->addElement('header', 'token', get_string('token', 'webservice'));
if (empty($data->nouserselection)) {
- //user searchable selector - get all users (admin and guest included)
- $sql = "SELECT u.id, u.firstname, u.lastname
- FROM {user} u
- ORDER BY u.lastname";
- $users = $DB->get_records_sql($sql, array());
- $options = array();
- foreach ($users as $userid => $user) {
- $options[$userid] = $user->firstname . " " . $user->lastname;
+
+ //check if the number of user is reasonable to be displayed in a select box
+ $usertotal = $DB->count_records('user',
+ array('deleted' => 0, 'suspended' => 0, 'confirmed' => 1));
+
+ if ($usertotal < 500) {
+ //user searchable selector - get all users (admin and guest included)
+ $users = $DB->get_records('user',
+ array('deleted' => 0, 'suspended' => 0, 'confirmed' => 1), 'lastname',
+ 'id, firstname, lastname');
+ $options = array();
+ foreach ($users as $userid => $user) {
+ $options[$userid] = $user->firstname . " " . $user->lastname;
+ }
+ $mform->addElement('searchableselector', 'user', get_string('user'), $options);
+ } else {
+ //simple text box for username or user id (if two username exists, a form error is displayed)
+ $mform->addElement('text', 'user', get_string('usernameorid', 'webservice'));
}
- $mform->addElement('searchableselector', 'user', get_string('user'), $options);
$mform->addRule('user', get_string('required'), 'required', null, 'client');
}
$this->set_data($data);
}
- function validation($data, $files) {
+ function get_data() {
+ global $DB;
+ $data = parent::get_data();
+
+ if (!empty($data) && !is_numeric($data->user)) {
+ //retrieve username
+ $user = $DB->get_record('user', array('username' => $data->user), 'id');
+ $data->user = $user->id;
+ }
+ return $data;
+ }
+
+ function validation(&$data, $files) {
+ global $DB;
+
$errors = parent::validation($data, $files);
+
+ if (is_numeric($data['user'])) {
+ $searchtype = 'id';
+ } else {
+ $searchtype = 'username';
+ //check the username is valid
+ if (clean_param($data['user'], PARAM_USERNAME) != $data['user']) {
+ $errors['user'] = get_string('invalidusername');
+ }
+ }
+
+ if (!isset($errors['user'])) {
+ $users = $DB->get_records('user', array($searchtype => $data['user']), '', 'id');
+
+ //check that the user exists in the database
+ if (count($users) == 0) {
+ $errors['user'] = get_string('usernameoridnousererror', 'webservice');
+ } else if (count($users) > 1) { //can only be a username search as id are unique
+ $errors['user'] = get_string('usernameoridoccurenceerror', 'webservice');
+ }
+ }
+
return $errors;
}
// 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);
+ // If this is not a course backup, inform the plan we are not
+ // including all the activities for sure. This will affect any
+ // task/step executed conditionally to stop including information
+ // for section and activity backup. MDL-28180.
+ if ($this->get_type() !== backup::TYPE_1COURSE) {
+ $this->log('notifying plan about excluded activities by type', backup::LOG_DEBUG);
+ $this->plan->set_excluding_activities();
+ }
return $this->plan->execute();
}
// 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);
+ // If this is not a course restore, inform the plan we are not
+ // including all the activities for sure. This will affect any
+ // task/step executed conditionally to stop processing information
+ // for section and activity restore. MDL-28180.
+ if ($this->get_type() !== backup::TYPE_1COURSE) {
+ $this->log('notifying plan about excluded activities by type', backup::LOG_DEBUG);
+ $this->plan->set_excluding_activities();
+ }
return $this->plan->execute();
}
$data->course = $this->get_courseid();
- $params = array(
- 'course' => $data->course,
- 'criteriatype' => $data->criteriatype,
- 'method' => $data->method,
- 'value' => $data->value,
- );
- $DB->insert_record('course_completion_aggr_methd', $params);
+ // Only create the course_completion_aggr_methd records if
+ // the target course has not them defined. MDL-28180
+ if (!$DB->record_exists('course_completion_aggr_methd', array(
+ 'course' => $data->course,
+ 'criteriatype' => $data->criteriatype))) {
+ $params = array(
+ 'course' => $data->course,
+ 'criteriatype' => $data->criteriatype,
+ 'method' => $data->method,
+ 'value' => $data->value,
+ );
+ $DB->insert_record('course_completion_aggr_methd', $params);
+ }
}
-
}
}
$this->controller = $controller;
$this->basepath = $CFG->tempdir . '/backup/' . $controller->get_backupid();
+ $this->excludingdactivities = false;
parent::__construct('backup_plan');
}
function get_content() {
global $USER, $CFG, $DB;
+ if (!has_capability('mod/glossary:read', $this->context)) {
+ return "";
+ }
+
if (empty($this->config->glossary)) {
$this->content->text = get_string('notyetconfigured','block_glossary_random');
$this->content->footer = '';
if ($PAGE->user_is_editing() && has_capability('moodle/course:update', $coursecontext)) {
echo '<a title="'.$streditsummary.'" '.
' href="editsection.php?id='.$thissection->id.'"><img src="'.$OUTPUT->pix_url('t/edit') . '" '.
- ' class="icon edit" alt="'.$streditsummary.'" /></a>';
+ ' class="iconsmall edit" alt="'.$streditsummary.'" /></a>';
}
echo '</div>';
if ($PAGE->user_is_editing() && has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $course->id))) {
echo ' <a title="'.$streditsummary.'" href="editsection.php?id='.$thissection->id.'">'.
- '<img src="'.$OUTPUT->pix_url('t/edit') . '" class="icon edit" alt="'.$streditsummary.'" /></a><br /><br />';
+ '<img src="'.$OUTPUT->pix_url('t/edit') . '" class="iconsmall edit" alt="'.$streditsummary.'" /></a><br /><br />';
}
echo '</div>';
if ($PAGE->user_is_editing() && has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $course->id))) {
echo '<p><a title="'.$streditsummary.'" '.
' href="editsection.php?id='.$thissection->id.'"><img src="'.$OUTPUT->pix_url('t/edit') . '" '.
- ' class="icon edit" alt="'.$streditsummary.'" /></a></p>';
+ ' class="iconsmall edit" alt="'.$streditsummary.'" /></a></p>';
}
echo '</div>';
if ($PAGE->user_is_editing() && has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $course->id))) {
echo ' <a title="'.$streditsummary.'" href="editsection.php?id='.$thissection->id.'">'.
- '<img src="'.$OUTPUT->pix_url('t/edit') . '" class="icon edit" alt="'.$streditsummary.'" /></a><br /><br />';
+ '<img src="'.$OUTPUT->pix_url('t/edit') . '" class="iconsmall edit" alt="'.$streditsummary.'" /></a><br /><br />';
}
echo '</div>';
$errors['availablefrom'] = get_string('badavailabledates', 'condition');
}
+ // Conditions: Verify that the grade conditions are numbers, and make sense.
+ if (array_key_exists('conditiongradegroup', $data)) {
+ foreach ($data['conditiongradegroup'] as $i => $gradedata) {
+ if ($gradedata['conditiongrademin'] !== '' && !is_numeric($gradedata['conditiongrademin'])) {
+ $errors["conditiongradegroup[{$i}]"] = get_string('gradesmustbenumeric', 'condition');
+ continue;
+ }
+ if ($gradedata['conditiongrademax'] !== '' && !is_numeric($gradedata['conditiongrademax'])) {
+ $errors["conditiongradegroup[{$i}]"] = get_string('gradesmustbenumeric', 'condition');
+ continue;
+ }
+ if ($gradedata['conditiongrademin'] !== '' && $gradedata['conditiongrademax'] !== '' &&
+ $gradedata['conditiongrademax'] < $gradedata['conditiongrademin']) {
+ $errors["conditiongradegroup[{$i}]"] = get_string('badgradelimits', 'condition');
+ continue;
+ }
+ if ($gradedata['conditiongrademin'] === '' && $gradedata['conditiongrademax'] === '' &&
+ $gradedata['conditiongradeitemid']) {
+ $errors["conditiongradegroup[{$i}]"] = get_string('gradeitembutnolimits', 'condition');
+ continue;
+ }
+ if (($gradedata['conditiongrademin'] !== '' || $gradedata['conditiongrademax'] !== '') &&
+ !$gradedata['conditiongradeitemid']) {
+ $errors["conditiongradegroup[{$i}]"] = get_string('gradelimitsbutnoitem', 'condition');
+ continue;
+ }
+ }
+ }
+
return $errors;
}
$grouparray[] =& $mform->createElement('static', '', '','% '.get_string('grade_upto','condition').' ');
$grouparray[] =& $mform->createElement('text', 'conditiongrademax','',array('size'=>3));
$grouparray[] =& $mform->createElement('static', '', '','%');
- $mform->setType('conditiongrademin',PARAM_FLOAT);
- $mform->setType('conditiongrademax',PARAM_FLOAT);
$group = $mform->createElement('group','conditiongradegroup',
get_string('gradecondition', 'condition'),$grouparray);
$coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
$personalcontext = get_context_instance(CONTEXT_USER, $user->id);
+$PAGE->set_url('/course/user.php', array('id'=>$id, 'user'=>$user->id, 'mode'=>$mode));
+
require_login();
$PAGE->set_pagelayout('admin');
if (has_capability('moodle/user:viewuseractivitiesreport', $personalcontext) and !is_enrolled($coursecontext)) {
if ($createcourses) {
require_once("$CFG->dirroot/course/lib.php");
- $template = $this->get_config('templatecourse');
+ $templatecourse = $this->get_config('templatecourse');
$defaultcategory = $this->get_config('defaultcategory');
- if ($template) {
- if ($template = $DB->get_record('course', array('shortname'=>$template))) {
+ $template = false;
+ if ($templatecourse) {
+ if ($template = $DB->get_record('course', array('shortname'=>$templatecourse))) {
unset($template->id);
unset($template->fullname);
unset($template->shortname);
unset($template->idnumber);
} else {
- $template = new stdClass();
+ if ($verbose) {
+ mtrace(" can not find template for new course!");
+ }
}
- } else {
+ }
+ if (!$template) {
+ $courseconfig = get_config('moodlecourse');
$template = new stdClass();
+ $template->summary = '';
+ $template->summaryformat = FORMAT_HTML;
+ $template->format = $courseconfig->format;
+ $template->numsections = $courseconfig->numsections;
+ $template->hiddensections = $courseconfig->hiddensections;
+ $template->newsitems = $courseconfig->newsitems;
+ $template->showgrades = $courseconfig->showgrades;
+ $template->showreports = $courseconfig->showreports;
+ $template->maxbytes = $courseconfig->maxbytes;
+ $template->groupmode = $courseconfig->groupmode;
+ $template->groupmodeforce = $courseconfig->groupmodeforce;
+ $template->visible = $courseconfig->visible;
+ $template->lang = $courseconfig->lang;
+ $template->groupmodeforce = $courseconfig->groupmodeforce;
}
if (!$DB->record_exists('course_categories', array('id'=>$defaultcategory))) {
+ if ($verbose) {
+ mtrace(" default course category does not exist!");
+ }
$categories = $DB->get_records('course_categories', array(), 'sortorder', 'id', 0, 1);
$first = reset($categories);
$defaultcategory = $first->id;
if (preg_match('{<sourcedid>.*?<id>(.+?)</id>.*?</sourcedid>}is', $tagcontents, $matches)) {
$group->coursecode = trim($matches[1]);
}
- if (preg_match('{<description>.*?<short>(.*?)</short>.*?</description>}is', $tagcontents, $matches)) {
+ if (preg_match('{<description>.*?<long>(.*?)</long>.*?</description>}is', $tagcontents, $matches)){
$group->description = trim($matches[1]);
}
+ if (preg_match('{<description>.*?<short>(.*?)</short>.*?</description>}is', $tagcontents, $matches)) {
+ $group->shortName = trim($matches[1]);
+ }
if (preg_match('{<org>.*?<orgunit>(.*?)</orgunit>.*?</org>}is', $tagcontents, $matches)) {
$group->category = trim($matches[1]);
}
if (!$createnewcourses) {
$this->log_line("Course $coursecode not found in Moodle's course idnumbers.");
} else {
+ // Set shortname to description or description to shortname if one is set but not the other.
+ $nodescription = !isset($group->description);
+ $noshortname = !isset($group->shortname);
+ if ( $nodescription && $noshortname) {
+ // If neither short nor long description are set let if fail
+ $this->log_line("Neither long nor short name are set for $coursecode");
+ } else if ($nodescription) {
+ // If short and ID exist, then give the long short's value, then give short the ID's value
+ $group->description = $group->shortName;
+ $group->shortName = $coursecode;
+ } else if ($noshortname) {
+ // If long and ID exist, then map long to long, then give short the ID's value.
+ $group->shortName = $coursecode;
+ }
// Create the (hidden) course(s) if not found
$courseconfig = get_config('moodlecourse'); // Load Moodle Course shell defaults
$course = new stdClass();
$course->fullname = $group->description;
- $course->shortname = $coursecode;
+ $course->shortname = $group->shortName;;
$course->idnumber = $coursecode;
$course->format = $courseconfig->format;
$course->visible = $courseconfig->visible;
require_once("$CFG->dirroot/course/lib.php");
// Override defaults with template course
- $course = new stdClass();
+ $template = false;
if ($this->get_config('template')) {
- if($template = $DB->get_record('course', array('shortname'=>$this->get_config('template')))) {
+ if ($template = $DB->get_record('course', array('shortname'=>$this->get_config('template')))) {
unset($template->id); // So we are clear to reinsert the record
unset($template->fullname);
unset($template->shortname);
unset($template->idnumber);
- $course = $template;
}
}
+ if (!$template) {
+ $courseconfig = get_config('moodlecourse');
+ $template = new stdClass();
+ $template->summary = '';
+ $template->summaryformat = FORMAT_HTML;
+ $template->format = $courseconfig->format;
+ $template->numsections = $courseconfig->numsections;
+ $template->hiddensections = $courseconfig->hiddensections;
+ $template->newsitems = $courseconfig->newsitems;
+ $template->showgrades = $courseconfig->showgrades;
+ $template->showreports = $courseconfig->showreports;
+ $template->maxbytes = $courseconfig->maxbytes;
+ $template->groupmode = $courseconfig->groupmode;
+ $template->groupmodeforce = $courseconfig->groupmodeforce;
+ $template->visible = $courseconfig->visible;
+ $template->lang = $courseconfig->lang;
+ $template->groupmodeforce = $courseconfig->groupmodeforce;
+ }
+ $course = $template;
$course->category = $this->get_config('category');
if (!$DB->record_exists('course_categories', array('id'=>$this->get_config('category')))) {
//--- role mapping settings ---
$settings->add(new admin_setting_heading('enrol_ldap_roles', get_string('roles', 'enrol_ldap'), ''));
if (!during_initial_install()) {
- $settings->add(new admin_setting_ldap_rolemapping('enrol_ldap/role_mapping', get_string ('role_mapping_key', 'enrol_ldap', $role->name), get_string ('role_mapping', 'enrol_ldap'), ''));
+ $settings->add(new admin_setting_ldap_rolemapping('enrol_ldap/role_mapping', get_string ('role_mapping_key', 'enrol_ldap'), get_string ('role_mapping', 'enrol_ldap'), ''));
}
$options = $yesno;
$settings->add(new admin_setting_configselect('enrol_ldap/course_search_sub', get_string('course_search_sub_key', 'enrol_ldap'), get_string('course_search_sub', 'enrol_ldap'), 0, $options));
$nothingtodo = false;
}
- if ($nothingtodo === true) {
+ if (($nothingtodo === true) || (!has_capability('mod/glossary:read', $this->context))) {
return $text;
}
$usercell->scope = 'row';
if ($showuserimage) {
- $usercell->text = $OUTPUT->container($OUTPUT->user_picture($user), 'userpic');
+ $usercell->text = $OUTPUT->user_picture($user);
}
$usercell->text .= html_writer::link(new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $this->course->id)), fullname($user));
background-color:#fff;
}
-.path-grade-report-grader div.userpic {
-margin-right:10px;
-float:left;
-}
-
-.path-grade-report-grader div.userpic img {
+.path-grade-report-grader th.user img {
border:3px double #cecece;
-vertical-align:middle;
+vertical-align:top;
width:2.7em;
height:2.7em;
+margin-right:10px;
}
.path-grade-report-grader a.quickedit {
The difference between access from/to dates and availability settings for the activity is that outside the set dates the latter allows students to view the activity description, whereas access from/to dates prevent access completely.';
$string['availableuntil'] = 'Allow access until';
$string['badavailabledates'] = 'Invalid dates. If you set both dates, the \'Allow access from\' date should be before the \'until\' date.';
+$string['badgradelimits'] = 'If you set both an upper and lower grade limit, the upper limit must be higher than the lower limit.';
$string['completion_complete'] = 'must be marked complete';
$string['completioncondition'] = 'Activity completion condition';
$string['completioncondition_help'] = 'This setting determines any activity completion conditions which must be met in order to access the activity. Note that completion tracking must first be set before an activity completion condition can be set.
Multiple grade conditions may be set if desired. If so, the activity will only allow access when ALL grade conditions are met.';
$string['grade_upto'] = 'and less than';
+$string['gradeitembutnolimits'] = 'You must enter an upper or lower limit, or both.';
+$string['gradelimitsbutnoitem'] = 'You must choose a grade item.';
+$string['gradesmustbenumeric'] = 'The minimum and maximum grades must be numeric (or blank).';
$string['none'] = '(none)';
$string['notavailableyet'] = 'Not available yet';
$string['requires_completion_0'] = 'Not available unless the activity <strong>{$a}</strong> is incomplete.';
$string['userasclients'] = 'Users as clients with token';
$string['userasclientsdescription'] = 'The following steps help you to set up the Moodle web service for users as clients. These steps also help to set up the recommended token (security keys) authentication method. In this use case, the user will generate his token from the security keys page via My profile settings.';
$string['usermissingcaps'] = 'Missing capabilities: {$a}';
+$string['usernameorid'] = 'Username / User id';
+$string['usernameorid_help'] = 'Enter a username or a user id.';
+$string['usernameoridnousererror'] = 'No users were found with this username/user id.';
+$string['usernameoridoccurenceerror'] = 'More than one user was found with this username. Please enter the user id.';
$string['usernotallowed'] = 'The user is not allowed for this service. First you need to allow this user on the {$a}\'s allowed users administration page.';
$string['usersettingssaved'] = 'User settings saved';
$string['validuntil'] = 'Valid until';
} else {
$newweight = ceil($newweight);
for ($weight = $bestgap - 1; $weight >= $newweight; $weight--) {
- foreach ($usedweights[$weight] as $biid) {
- $this->reposition_block($biid, $newregion, $weight + 1);
+ if (array_key_exists($weight, $usedweights)) {
+ foreach ($usedweights[$weight] as $biid) {
+ $this->reposition_block($biid, $newregion, $weight + 1);
+ }
}
}
$this->reposition_block($block->instance->id, $newregion, $newweight);
// Moodle v2.2.0 release upgrade line
// Put any upgrade step following this
+ if ($oldversion < 2011120500.02) {
+
+ upgrade_set_timeout(60*20); // This may take a while
+ // MDL-28180. Some missing restrictions in certain backup & restore operations
+ // were causing incorrect duplicates in the course_completion_aggr_methd table.
+ // This upgrade step takes rid of them.
+ $sql = 'SELECT course, criteriatype, MIN(id) AS minid
+ FROM {course_completion_aggr_methd}
+ GROUP BY course, criteriatype
+ HAVING COUNT(*) > 1';
+ $duprs = $DB->get_recordset_sql($sql);
+ foreach ($duprs as $duprec) {
+ // We need to handle NULLs in criteriatype diferently
+ if (is_null($duprec->criteriatype)) {
+ $where = 'course = ? AND criteriatype IS NULL AND id > ?';
+ $params = array($duprec->course, $duprec->minid);
+ } else {
+ $where = 'course = ? AND criteriatype = ? AND id > ?';
+ $params = array($duprec->course, $duprec->criteriatype, $duprec->minid);
+ }
+ $DB->delete_records_select('course_completion_aggr_methd', $where, $params);
+ }
+ $duprs->close();
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2011120500.02);
+ }
+
return true;
}
$access = false;
- if (is_viewing($coursecontext, $USER)) {
+ if (is_role_switched($course->id)) {
+ // ok, user had to be inside this course before the switch
+ $access = true;
+
+ } else if (is_viewing($coursecontext, $USER)) {
// ok, no need to mess with enrol
$access = true;
}
}
if ($gradeaccess) {
- $reporttab->add(get_string('grade'), new moodle_url('/course/user.php', array('mode'=>'grade', 'id'=>$course->id)));
+ $reporttab->add(get_string('grade'), new moodle_url('/course/user.php', array('mode'=>'grade', 'id'=>$course->id, 'user'=>$usercontext->instanceid)));
}
}
// Check the number of nodes in the report node... if there are none remove the node
* @return moodle_url
*/
public function get_url(moodle_page $page, renderer_base $renderer = null) {
- global $CFG, $FULLME;
+ global $CFG;
if (is_null($renderer)) {
$renderer = $page->get_renderer('core');
// Build a gravatar URL with what we know.
// If the currently requested page is https then we'll return an
// https gravatar page.
- if (strpos($FULLME, 'https://') === 0) {
+ if (strpos($CFG->httpswwwroot, 'https:') === 0) {
$imageurl = new moodle_url("https://secure.gravatar.com/avatar/{$md5}", array('s' => $size, 'd' => $imageurl->out(false)));
} else {
$imageurl = new moodle_url("http://www.gravatar.com/avatar/{$md5}", array('s' => $size, 'd' => $imageurl->out(false)));
if (debugging('', DEBUG_DEVELOPER)) {
$this->yui3loader->filter = YUI_RAW; // for more detailed logging info use YUI_DEBUG here
$this->yui2loader->filter = YUI_RAW; // for more detailed logging info use YUI_DEBUG here
+ $this->yui2loader->allowRollups = false;
} else {
$this->yui3loader->filter = null;
$this->yui2loader->filter = null;
$this->M_yui_loader->base = $this->yui3loader->base;
$this->M_yui_loader->comboBase = $this->yui3loader->comboBase;
$this->M_yui_loader->combine = $this->yui3loader->combine;
- $this->M_yui_loader->filter = ($this->yui3loader->filter == YUI_DEBUG) ? 'debug' : '';
+ $this->M_yui_loader->filter = (string)$this->yui3loader->filter;
$this->M_yui_loader->insertBefore = 'firstthemesheet';
$this->M_yui_loader->modules = array();
$this->M_yui_loader->groups = array(
* Initialise with the bits of JavaScript that every Moodle page should have.
*
* @param moodle_page $page
- * @param core_renderer $output
+ * @param core_renderer $renderer
*/
protected function init_requirements_data(moodle_page $page, core_renderer $renderer) {
global $CFG;
/**
* Returns true if the module has already been loaded.
*
- * @param string|array $modulename
+ * @param string|array $module
* @return bool True if the module has already been loaded
*/
protected function js_module_loaded($module) {
* (e.g. and array) that you pass to JavaScript with {@link data_for_js()}.
*
* @param string $identifier the desired string.
- * @param string $module the language file to look in.
+ * @param string $component the language file to look in.
* @param mixed $a any extra data to add into the string (optional).
*/
public function string_for_js($identifier, $component, $a = NULL) {
/**
* Get the inline JavaScript code that need to appear in a particular place.
- * @return bool $ondomready
+ * @param bool $ondomready
+ * @return string
*/
protected function get_javascript_code($ondomready) {
$where = $ondomready ? 'ondomready' : 'normal';
$code .= '<link rel="stylesheet" type="text/css" href="'.$this->yui3loader->base.'cssbase/base-min.css" />';
}
- if (debugging('', DEBUG_DEVELOPER)) {
- $code .= '<script type="text/javascript" src="'.$this->yui3loader->base.'yui/yui-debug.js"></script>';
- } else {
- $code .= '<script type="text/javascript" src="'.$this->yui3loader->base.'yui/yui-min.js"></script>';
+ $code .= '<script type="text/javascript" src="'.$this->yui3loader->base.'yui/yui-min.js"></script>';
+
+ if ($this->yui3loader->filter === YUI_RAW) {
+ $code = str_replace('-min.css', '.css', $code);
+ $code = str_replace('-min.js', '.js', $code);
+ } else if ($this->yui3loader->filter === YUI_DEBUG) {
+ $code = str_replace('-min.css', '.css', $code);
+ $code = str_replace('-min.js', '-debug.js', $code);
}
return $code;
/**
* Adds extra modules specified after printing of page header
+ * @return string
*/
protected function get_extra_modules_code() {
if (empty($this->extramodules)) {
* Normally, this method is called automatically by the code that prints the
* <head> tag. You should not normally need to call it in your own code.
*
+ * @param moodle_page $page
+ * @param core_renderer $renderer
* @return string the HTML code to to inside the <head> tag.
*/
public function get_head_code(moodle_page $page, core_renderer $renderer) {
}
// now the real test and redirect!
+ // NOTE: do NOT use this test for detection of https on current page because this code is not compatible with SSL proxies,
+ // instead use strpos($CFG->httpswwwroot, 'https:') === 0
if (strpos($FULLME, 'https:') !== 0) {
// this may lead to infinite redirect on misconfigured sites, in that case use $CFG->loginhttps=0; in /config.php
redirect($this->_url);
$result .= $this->HeaderLine('Date', self::RFCDate());
if($this->Sender == '') {
- $result .= $this->HeaderLine('Return-Path', trim($this->From));
+ $result .= $this->HeaderLine('Return-Path', trim($this->SecureHeader($this->From))); // Moodle modification
} else {
- $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
+ $result .= $this->HeaderLine('Return-Path', trim($this->SecureHeader($this->Sender))); // Moodle modification
}
// To be created automatically by mail()
/**
* Enter description here...
*
- * @param string $questionids list of questionids
+ * @param array $questionids of question ids
* @param object $newcontext the context to create the saved category in.
* @param string $oldplace a textual description of the think being deleted,
* e.g. from get_context_name
* function also have to do other work, which is why you should not call this method
* directly from outside the questionbank.
*
- * @param string $questionids a comma-separated list of question ids.
+ * @param array $questionids of question ids.
* @param integer $newcategoryid the id of the category to move to.
*/
function question_move_questions_to_category($questionids, $newcategoryid) {
/**
* Full script path including all params, slash arguments, scheme and host.
+ *
+ * Note: Do NOT use for getting of current page URL or detection of https,
+ * instead use $PAGE->url or strpos($CFG->httpswwwroot, 'https:') === 0
+ *
* @global string $FULLME
* @name $FULLME
*/
*/
function make_temp_directory($directory, $exceptiononerror = true) {
global $CFG;
- protect_directory($CFG->tempdir);
+ if ($CFG->tempdir !== "$CFG->dataroot/temp") {
+ check_dir_exists($CFG->tempdir, true, true);
+ protect_directory($CFG->tempdir);
+ } else {
+ protect_directory($CFG->dataroot);
+ }
return make_writable_directory("$CFG->tempdir/$directory", $exceptiononerror);
}
*/
function make_cache_directory($directory, $exceptiononerror = true) {
global $CFG;
- protect_directory($CFG->cachedir);
+ if ($CFG->cachedir !== "$CFG->dataroot/cache") {
+ check_dir_exists($CFG->cachedir, true, true);
+ protect_directory($CFG->cachedir);
+ } else {
+ protect_directory($CFG->dataroot);
+ }
return make_writable_directory("$CFG->cachedir/$directory", $exceptiononerror);
}
$capabilities = array(
+ 'mod/glossary:read' => array(
+
+ 'captype' => 'read',
+ 'contextlevel' => CONTEXT_MODULE,
+ 'archetypes' => array(
+ 'guest' => CAP_ALLOW,
+ 'student' => CAP_ALLOW,
+ 'teacher' => CAP_ALLOW,
+ 'editingteacher' => CAP_ALLOW,
+ 'manager' => CAP_ALLOW
+ )
+ ),
+
+
'mod/glossary:write' => array(
'riskbitmask' => RISK_SPAM,
$options = array();
$options['current'] = get_string('currentglossary', 'glossary');
$options['newglossary'] = get_string('newglossary', 'glossary');
- $mform->addElement('select', 'dest', get_string('currentglossary', 'glossary'), $options);
+ $mform->addElement('select', 'dest', get_string('destination', 'glossary'), $options);
$mform->addHelpButton('dest', 'destination', 'glossary');
$mform->addElement('checkbox', 'catsincl', get_string('importcategories', 'glossary'));
$submit_string = get_string('submit');
$string['glossary:managecomments'] = 'Manage comments';
$string['glossary:manageentries'] = 'Manage entries';
$string['glossary:rate'] = 'Rate entries';
+$string['glossary:read'] = 'Read entries';
$string['glossarytype'] = 'Glossary type';
$string['glossarytype_help'] = 'A main glossary is a glossary in which entries from secondary glossaries can be imported. There can only be one main glossary in a course. if glossary entry import is not required, all glossaries in the course can be secondary glossaries.';
$string['glossary:view'] = 'View glossary';
* @return bool
*/
function glossary_print_recent_activity($course, $viewfullnames, $timestart) {
- global $CFG, $USER, $DB, $OUTPUT;
+ global $CFG, $USER, $DB, $OUTPUT, $PAGE;
//TODO: use timestamp in approved field instead of changing timemodified when approving in 2.0
if (!defined('GLOSSARY_RECENT_ACTIVITY_LIMIT')) {
$approvals = array();
foreach ($ids as $glinstanceid => $glcmid) {
$context = get_context_instance(CONTEXT_MODULE, $glcmid);
+ if (!has_capability('mod/glossary:read', $context)) {
+ continue;
+ }
// get records glossary entries that are approved if user has no capability to approve entries.
if (has_capability('mod/glossary:approve', $context)) {
$approvals[] = ' ge.glossaryid = :glsid'.$glinstanceid.' ';
$glossary = $DB->get_record('glossary', array("id" => $PAGE->cm->instance));
- if (!empty($CFG->enablerssfeeds) && !empty($CFG->glossary_enablerssfeeds) && $glossary->rsstype && $glossary->rssarticles && can_access_course($PAGE->course, $USER)) {
+ if (!empty($CFG->enablerssfeeds) && !empty($CFG->glossary_enablerssfeeds) && $glossary->rsstype && $glossary->rssarticles && has_capability('mod/glossary:read', $PAGE->cm->context)) {
require_once("$CFG->libdir/rsslib.php");
$string = get_string('rsstype','forum');
$course = $DB->get_record('course', array('id'=>$cm->course), '*', MUST_EXIST);
}
//context id from db should match the submitted one
- //no specific capability required to view glossary entries so just check user is enrolled
- if ($context->id != $modcontext->id || !can_access_course($course, $USER)) {
+ if ($context->id != $modcontext->id || !has_capability('mod/glossary:read', $modcontext)) {
return null;
}
}
defined('MOODLE_INTERNAL') || die();
-$module->version = 2011112900; // The current module version (Date: YYYYMMDDXX)
+$module->version = 2011120200; // The current module version (Date: YYYYMMDDXX)
$module->requires = 2011112900; // Requires this Moodle version
$module->component = 'mod_glossary'; // Full name of the plugin (used for diagnostics)
$module->cron = 0;
require_course_login($course->id, true, $cm);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
+require_capability('mod/glossary:read', $context);
// Prepare format_string/text options
$fmtoptions = array(
$yeslink = html_writer::link(new moodle_url('/mod/lesson/view.php', array('id'=>$this->page->cm->id, 'pageid'=>$lastpageseenid, 'startlastseen'=>'yes')), get_string('yes'));
$output .= html_writer::tag('span', $yeslink, array('class'=>'lessonbutton standardbutton'));
+ $output .= ' ';
$nolink = html_writer::link(new moodle_url('/mod/lesson/view.php', array('id'=>$this->page->cm->id, 'pageid'=>$lesson->firstpageid, 'startlastseen'=>'no')), get_string('no'));
$output .= html_writer::tag('span', $nolink, array('class'=>'lessonbutton standardbutton'));
}
function lti_request_is_using_ssl() {
- global $FULLME;
- return (stripos($FULLME, 'https://') === 0);
+ global $CFG;
+ return (stripos($CFG->httpswwwroot, 'https://') === 0);
}
function lti_ensure_url_is_https($url) {
if (groups_get_activity_groupmode($cm)) {
$a->total = $numattempts;
if ($currentgroup) {
- $a->group = $DB->count_records_sql('SELECT count(1) FROM ' .
+ $a->group = $DB->count_records_sql('SELECT COUNT(DISTINCT qa.id) FROM ' .
'{quiz_attempts} qa JOIN ' .
'{groups_members} gm ON qa.userid = gm.userid ' .
'WHERE quiz = ? AND preview = 0 AND groupid = ?',
return get_string('attemptsnumthisgroup', 'quiz', $a);
} else if ($groups = groups_get_all_groups($cm->course, $USER->id, $cm->groupingid)) {
list($usql, $params) = $DB->get_in_or_equal(array_keys($groups));
- $a->group = $DB->count_records_sql('SELECT count(1) FROM ' .
+ $a->group = $DB->count_records_sql('SELECT COUNT(DISTINCT qa.id) FROM ' .
'{quiz_attempts} qa JOIN ' .
'{groups_members} gm ON qa.userid = gm.userid ' .
'WHERE quiz = ? AND preview = 0 AND ' .
$userdata->student_id = addslashes_js($USER->username);
$userdata->student_name = addslashes_js($USER->lastname .', '. $USER->firstname);
$userdata->mode = 'normal';
-if (isset($mode)) {
+if (!empty($mode)) {
$userdata->mode = $mode;
}
if ($userdata->mode == 'normal') {
'cmi.learner_id':{'defaultvalue':'<?php echo $userdata->student_id ?>', 'mod':'r'},
'cmi.learner_name':{'defaultvalue':'<?php echo $userdata->student_name ?>', 'mod':'r'},
'cmi.learner_preference._children':{'defaultvalue':student_preference_children, 'mod':'r'},
- 'cmi.learner_preference.audio_level':{'defaultvalue':'1', 'format':CMIDecimal, 'range':audio_range, 'mod':'rw'},
- 'cmi.learner_preference.language':{'defaultvalue':'', 'format':CMILang, 'mod':'rw'},
- 'cmi.learner_preference.delivery_speed':{'defaultvalue':'1', 'format':CMIDecimal, 'range':speed_range, 'mod':'rw'},
- 'cmi.learner_preference.audio_captioning':{'defaultvalue':'0', 'format':CMISInteger, 'range':text_range, 'mod':'rw'},
+ 'cmi.learner_preference.audio_level':{'defaultvalue':<?php echo !empty($userdata->{'cmi.learner_preference.audio_level'})?'\''.$userdata->{'cmi.learner_preference.audio_level'}.'\'':'\'1\'' ?>, 'format':CMIDecimal, 'range':audio_range, 'mod':'rw'},
+ 'cmi.learner_preference.language':{'defaultvalue':<?php echo !empty($userdata->{'cmi.learner_preference.language'})?'\''.$userdata->{'cmi.learner_preference.language'}.'\'':'\'\'' ?>, 'format':CMILang, 'mod':'rw'},
+ 'cmi.learner_preference.delivery_speed':{'defaultvalue':<?php echo !empty($userdata->{'cmi.learner_preference.delivery_speed'})?'\''.$userdata->{'cmi.learner_preference.delivery_speed'}.'\'':'\'1\'' ?>, 'format':CMIDecimal, 'range':speed_range, 'mod':'rw'},
+ 'cmi.learner_preference.audio_captioning':{'defaultvalue':<?php echo !empty($userdata->{'cmi.learner_preference.audio_captioning'})?'\''.$userdata->{'cmi.learner_preference.audio_captioning'}.'\'':'\'0\'' ?>, 'format':CMISInteger, 'range':text_range, 'mod':'rw'},
'cmi.location':{'defaultvalue':<?php echo !empty($userdata->{'cmi.location'})?'\''.$userdata->{'cmi.location'}.'\'':'null' ?>, 'format':CMIString1000, 'mod':'rw'},
'cmi.max_time_allowed':{'defaultvalue':<?php echo !empty($userdata->attemptAbsoluteDurationLimit)?'\''.$userdata->attemptAbsoluteDurationLimit.'\'':'null' ?>, 'mod':'r'},
'cmi.mode':{'defaultvalue':'<?php echo $userdata->mode ?>', 'mod':'r'},
'cmi.objectives.n.completion_status':{'defaultvalue':'unknown', 'pattern':CMIIndex, 'format':CMICStatus, 'mod':'rw'},
'cmi.objectives.n.progress_measure':{'defaultvalue':null, 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'},
'cmi.objectives.n.description':{'pattern':CMIIndex, 'format':CMILangString250, 'mod':'rw'},
- 'cmi.progress_measure':{'defaultvalue':<?php echo !empty($userdata->{'cmi.progess_measure'})?'\''.$userdata->{'cmi.progress_measure'}.'\'':'null' ?>, 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'},
+ 'cmi.progress_measure':{'defaultvalue':<?php echo !empty($userdata->{'cmi.progress_measure'})?'\''.$userdata->{'cmi.progress_measure'}.'\'':'null' ?>, 'format':CMIDecimal, 'range':progress_range, 'mod':'rw'},
'cmi.scaled_passing_score':{'defaultvalue':<?php echo !empty($userdata->{'cmi.scaled_passing_score'})?'\''.$userdata->{'cmi.scaled_passing_score'}.'\'':'null' ?>, 'format':CMIDecimal, 'range':scaled_range, 'mod':'r'},
'cmi.score._children':{'defaultvalue':score_children, 'mod':'r'},
'cmi.score.scaled':{'defaultvalue':<?php echo !empty($userdata->{'cmi.score.scaled'})?'\''.$userdata->{'cmi.score.scaled'}.'\'':'null' ?>, 'format':CMIDecimal, 'range':scaled_range, 'mod':'rw'},
if (has_capability('moodle/course:viewparticipants', $coursecontext) || has_capability('moodle/site:viewparticipants', $systemcontext)) {
$link = new moodle_url('/user/index.php',array('id'=>$course->id));
}
- $PAGE->navbar->add(get_string('participants'), $link);
- $PAGE->navbar->add($strnotes);
}
$PAGE->set_pagelayout('course');
*/
$string['gradingdetails'] = 'Marks for this submission: {$a->raw}/{$a->max}.';
-$string['gradingdetailsadjustment'] = 'With previous penalties this gives <strong>{$a->cur}/{$a->max}</strong>.';
+$string['gradingdetailsadjustment'] = 'Accounting for previous tries, this gives <strong>{$a->cur}/{$a->max}</strong>.';
$string['gradingdetailspenalty'] = 'This submission attracted a penalty of {$a}.';
+$string['gradingdetailspenaltytotal'] = 'Total penalties so far: {$a}.';
$string['notcomplete'] = 'Not complete';
$string['pluginname'] = 'Adaptive mode';
*/
protected function penalty_info(question_attempt $qa, $mark,
question_display_options $options) {
- if (!$qa->get_question()->penalty) {
+
+ $currentpenalty = $qa->get_question()->penalty * $qa->get_max_mark();
+ $totalpenalty = $currentpenalty * $qa->get_last_behaviour_var('_try', 0);
+
+ if ($currentpenalty == 0) {
return '';
}
$output = '';
// Print information about any new penalty, only relevant if the answer can be improved.
if ($qa->get_behaviour()->is_state_improvable($qa->get_state())) {
$output .= ' ' . get_string('gradingdetailspenalty', 'qbehaviour_adaptive',
- format_float($qa->get_question()->penalty, $options->markdp));
+ format_float($currentpenalty, $options->markdp));
+
+ // Print information about total penalties so far, if larger than current penalty.
+ if ($totalpenalty > $currentpenalty) {
+ $output .= ' ' . get_string('gradingdetailspenaltytotal', 'qbehaviour_adaptive',
+ format_float($totalpenalty, $options->markdp));
+ }
}
return $output;
return new NoPatternExpectation($penaltypattern);
}
+ protected function get_contains_total_penalty_expectation($penalty) {
+ $penaltyinfo = get_string('gradingdetailspenaltytotal', 'qbehaviour_adaptive',
+ format_float($penalty, $this->displayoptions->markdp));
+ return new PatternExpectation('/'.preg_quote($penaltyinfo).'/');
+ }
+
+ protected function get_does_not_contain_total_penalty_expectation() {
+ $penaltyinfo = get_string('gradingdetailspenaltytotal', 'qbehaviour_adaptive', 'XXXXX');
+ $penaltypattern = '/'.str_replace('XXXXX', '\\w*', preg_quote($penaltyinfo)).'/';
+ return new NoPatternExpectation($penaltypattern);
+ }
+
public function test_adaptive_multichoice() {
// Create a multiple choice, single response question.
$this->get_contains_mc_radio_expectation(($wrongindex + 1) % 3, true, false),
$this->get_contains_mc_radio_expectation(($wrongindex + 2) % 3, true, false),
$this->get_contains_incorrect_expectation(),
- $this->get_contains_penalty_info_expectation(0.33));
+ $this->get_contains_penalty_info_expectation(1.00),
+ $this->get_does_not_contain_total_penalty_expectation());
$this->assertPattern('/B|C/',
$this->quba->get_response_summary($this->slot));
$this->get_contains_mc_radio_expectation(($rightindex + 1) % 3, true, false),
$this->get_contains_mc_radio_expectation(($rightindex + 2) % 3, true, false),
$this->get_contains_correct_expectation(),
- $this->get_does_not_contain_penalty_info_expectation());
+ $this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_total_penalty_expectation());
$this->assertEqual('A',
$this->quba->get_response_summary($this->slot));
$this->get_contains_mark_summary(2),
$this->get_contains_submit_button_expectation(true),
$this->get_contains_correct_expectation(),
- $this->get_does_not_contain_penalty_info_expectation());
+ $this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_total_penalty_expectation());
// Save the same correct answer again. Should not do anything.
$numsteps = $this->get_step_count();
$this->get_contains_submit_button_expectation(true),
$this->get_contains_partcorrect_expectation(),
$this->get_contains_penalty_info_expectation(0.33),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_does_not_contain_validation_error_expectation());
// Submit an incorrect answer.
$this->get_contains_submit_button_expectation(true),
$this->get_contains_incorrect_expectation(),
$this->get_contains_penalty_info_expectation(0.33),
+ $this->get_contains_total_penalty_expectation(0.67),
$this->get_does_not_contain_validation_error_expectation());
// Submit a correct answer.
$this->get_contains_submit_button_expectation(true),
$this->get_contains_correct_expectation(),
$this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_does_not_contain_validation_error_expectation());
// Finish the attempt.
// Create a short answer question
$sa = test_question_maker::make_a_shortanswer_question();
- $this->start_attempt_at_question($sa, 'adaptive');
+ $this->start_attempt_at_question($sa, 'adaptive', 6);
// Check the initial state.
$this->check_current_state(question_state::$todo);
$this->get_contains_mark_summary(0),
$this->get_contains_submit_button_expectation(true),
$this->get_contains_incorrect_expectation(),
- $this->get_contains_penalty_info_expectation(0.33),
+ $this->get_contains_penalty_info_expectation(2.00),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_does_not_contain_validation_error_expectation());
// Submit the same wrong answer again. Nothing should change.
$this->get_contains_mark_summary(0),
$this->get_contains_submit_button_expectation(true),
$this->get_contains_incorrect_expectation(),
- $this->get_contains_penalty_info_expectation(0.33),
+ $this->get_contains_penalty_info_expectation(2.00),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_does_not_contain_validation_error_expectation());
// Submit a correct answer.
// Verify.
$this->check_current_state(question_state::$complete);
- $this->check_current_mark(0.66666667);
+ $this->check_current_mark(4.00);
$this->check_current_output(
- $this->get_contains_mark_summary(0.67),
+ $this->get_contains_mark_summary(4.00),
$this->get_contains_submit_button_expectation(true),
$this->get_contains_correct_expectation(),
$this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_does_not_contain_validation_error_expectation());
// Submit another incorrect answer.
// Verify.
$this->check_current_state(question_state::$complete);
- $this->check_current_mark(0.66666667);
+ $this->check_current_mark(4.00);
$this->check_current_output(
- $this->get_contains_mark_summary(0.67),
+ $this->get_contains_mark_summary(4.00),
$this->get_contains_submit_button_expectation(true),
$this->get_contains_incorrect_expectation(),
$this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_does_not_contain_validation_error_expectation());
// Finish the attempt.
// Verify.
$this->check_current_state(question_state::$gradedwrong);
- $this->check_current_mark(0.66666667);
+ $this->check_current_mark(4.00);
$this->check_current_output(
- $this->get_contains_mark_summary(0.67),
+ $this->get_contains_mark_summary(4.00),
$this->get_contains_submit_button_expectation(false),
$this->get_contains_incorrect_expectation(),
$this->get_does_not_contain_validation_error_expectation());
$this->get_contains_submit_button_expectation(true),
$this->get_contains_incorrect_expectation(),
$this->get_contains_penalty_info_expectation(0.33),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_does_not_contain_validation_error_expectation());
// Submit a correct answer.
$this->get_contains_submit_button_expectation(true),
$this->get_contains_correct_expectation(),
$this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_does_not_contain_validation_error_expectation());
// Submit an empty answer.
$this->get_contains_mark_summary(0.67),
$this->get_contains_submit_button_expectation(true),
$this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_contains_validation_error_expectation());
// Submit another wrong answer.
$this->get_contains_submit_button_expectation(true),
$this->get_contains_incorrect_expectation(),
$this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_does_not_contain_validation_error_expectation());
// Finish the attempt.
$this->get_does_not_contain_validation_error_expectation());
}
+ public function test_adaptive_shortanswer_zero_penalty() {
+
+ // Create a short answer question
+ $sa = test_question_maker::make_a_shortanswer_question();
+ // Disable penalties for this question
+ $sa->penalty = 0;
+ $this->start_attempt_at_question($sa, 'adaptive');
+
+ // Check the initial state.
+ $this->check_current_state(question_state::$todo);
+ $this->check_current_mark(null);
+ $this->check_current_output(
+ $this->get_contains_marked_out_of_summary(),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_does_not_contain_feedback_expectation());
+
+ // Submit a wrong answer.
+ $this->process_submission(array('-submit' => 1, 'answer' => 'hippopotamus'));
+
+ // Verify.
+ $this->check_current_state(question_state::$todo);
+ $this->check_current_mark(0);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_contains_incorrect_expectation(),
+ $this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_total_penalty_expectation(),
+ $this->get_does_not_contain_validation_error_expectation());
+
+ // Submit a correct answer.
+ $this->process_submission(array('-submit' => 1, 'answer' => 'frog'));
+
+ // Verify.
+ $this->check_current_state(question_state::$complete);
+ $this->check_current_mark(1.0);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(1.0),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_contains_correct_expectation(),
+ $this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_total_penalty_expectation(),
+ $this->get_does_not_contain_validation_error_expectation());
+
+ // Finish the attempt.
+ $this->quba->finish_all_questions();
+
+ // Verify.
+ $this->check_current_state(question_state::$gradedright);
+ $this->check_current_mark(1.0);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(1.0),
+ $this->get_contains_submit_button_expectation(false),
+ $this->get_contains_correct_expectation(),
+ $this->get_does_not_contain_validation_error_expectation());
+ }
+
public function test_adaptive_shortanswer_try_to_submit_blank() {
// Create a short answer question with correct answer true.
$this->get_contains_submit_button_expectation(true),
$this->get_does_not_contain_correctness_expectation(),
$this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_contains_validation_error_expectation());
$this->assertNull($this->quba->get_response_summary($this->slot));
$this->get_contains_submit_button_expectation(true),
$this->get_contains_partcorrect_expectation(),
$this->get_contains_penalty_info_expectation(0.33),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_does_not_contain_validation_error_expectation());
// Now submit blank again.
$this->get_contains_submit_button_expectation(true),
$this->get_contains_partcorrect_expectation(),
$this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_contains_validation_error_expectation());
}
$this->get_contains_submit_button_expectation(true),
$this->get_contains_correct_expectation(),
$this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_does_not_contain_validation_error_expectation());
// Submit an incorrect answer.
$this->get_contains_submit_button_expectation(true),
$this->get_contains_incorrect_expectation(),
$this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_total_penalty_expectation(),
$this->get_does_not_contain_validation_error_expectation());
// Finish the attempt.
global $DB;
$questionids = $DB->get_records_select_menu('question',
'category = ? AND (parent = 0 OR parent = id)', array($oldcat), '', 'id,1');
- question_move_questions_to_category($questionids, $newcat);
+ question_move_questions_to_category(array_keys($questionids), $newcat);
}
/**
* If you use extra_question_fields, overload this function to return question id field name
* in case you table use another name for this column
*/
- protected function questionid_column_name() {
+ public function questionid_column_name() {
return 'questionid';
}
*
* @return mixed array as above, or null to tell the base class to do nothing.
*/
- protected function extra_answer_fields() {
+ public function extra_answer_fields() {
return null;
}
return array('question_shortanswer', 'answers', 'usecase');
}
- protected function questionid_column_name() {
+ public function questionid_column_name() {
return 'question';
}
$string['pluginnamesummary'] = 'This is not actually a question. Instead it is a way to add some instructions, rubric or other content to the activity. This is similar to the way that labels can be used to add content to the course page.';
The old strings will continue to work, but only until Moodle 2.3 is released.
+
+* If you are using the facilities provided by overriding the extra_answer_fields
+ or questionid_column_name methods, then you must change these to be public
+ methods. (This is required so that backup and restore can be made to work
+ automatically. MDL-24408, MDL-25617, MDL-30562)
$isseparategroups = ($course->groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context));
- if ($course->id===SITEID) {
- $PAGE->navbar->ignore_active();
- }
-
- $PAGE->navbar->add(get_string('participants'));
$PAGE->set_title("$course->shortname: ".get_string('participants'));
$PAGE->set_heading($course->fullname);
$PAGE->set_pagetype('course-view-' . $course->format);
if (!isset($hiddenfields['lastaccess'])) {
$table->sortable(true, 'lastaccess', SORT_DESC);
+ } else {
+ $table->sortable(true, 'firstname', SORT_ASC);
}
$table->no_sorting('roles');
/// insert the user into the database
$newuserid = $DB->insert_record('user', $user);
+/// trigger user_created event on the full database user row
+ $newuser = $DB->get_record('user', array('id' => $newuserid));
+ events_trigger('user_created', $newuser);
+
/// create USER context for this user
get_context_instance(CONTEXT_USER, $newuserid);
$user->timemodified = time();
$DB->update_record('user', $user);
+
+ /// trigger user_updated event on the full database user row
+ $updateduser = $DB->get_record('user', array('id' => $user->id));
+ events_trigger('user_updated', $updateduser);
+
}
defined('MOODLE_INTERNAL') || die();
-$version = 2011120500.01; // YYYYMMDD = weekly release date of this DEV branch
+$version = 2011120500.02; // YYYYMMDD = weekly release date of this DEV branch
// RR = release increments - 00 in DEV branches
// .XX = incremental changes