mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 06:18:28 +01:00
MDL-22414 Merge branch 'master' into backup-convert
Conflicts: theme/base/style/core.css
This commit is contained in:
commit
b61cf3ff8a
@ -622,7 +622,7 @@ class generator {
|
||||
require_once($CFG->libdir .'/questionlib.php');
|
||||
require_once($CFG->dirroot .'/mod/quiz/editlib.php');
|
||||
$questions = array();
|
||||
$questionsmenu = question_type_menu();
|
||||
$questionsmenu = question_bank::get_creatable_qtypes();
|
||||
$questiontypes = array();
|
||||
foreach ($questionsmenu as $qtype => $qname) {
|
||||
$questiontypes[] = $qtype;
|
||||
|
@ -355,7 +355,6 @@ if (during_initial_install()) {
|
||||
}
|
||||
// login user and let him set password and admin details
|
||||
$adminuser->newadminuser = 1;
|
||||
message_set_default_message_preferences($adminuser);
|
||||
complete_user_login($adminuser, false);
|
||||
redirect("$CFG->wwwroot/user/editadvanced.php?id=$adminuser->id"); // Edit thyself
|
||||
|
||||
|
70
admin/message.php
Normal file
70
admin/message.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Message outputs configuration page
|
||||
*
|
||||
* @package message
|
||||
* @copyright 2011 Lancaster University Network Services Limited
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/../config.php');
|
||||
require_once($CFG->dirroot . '/message/lib.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
|
||||
// This is an admin page
|
||||
admin_externalpage_setup('managemessageoutputs');
|
||||
|
||||
// Require site configuration capability
|
||||
require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
|
||||
|
||||
// Get the submitted params
|
||||
$disable = optional_param('disable', 0, PARAM_INT);
|
||||
$enable = optional_param('enable', 0, PARAM_INT);
|
||||
|
||||
if (!empty($disable) && confirm_sesskey()) {
|
||||
if (!$processor = $DB->get_record('message_processors', array('id'=>$disable))) {
|
||||
print_error('outputdoesnotexist', 'message');
|
||||
}
|
||||
$DB->set_field('message_processors', 'enabled', '0', array('id'=>$processor->id)); // Disable output
|
||||
}
|
||||
|
||||
if (!empty($enable) && confirm_sesskey() ) {
|
||||
if (!$processor = $DB->get_record('message_processors', array('id'=>$enable))) {
|
||||
print_error('outputdoesnotexist', 'message');
|
||||
}
|
||||
$DB->set_field('message_processors', 'enabled', '1', array('id'=>$processor->id)); // Enable output
|
||||
}
|
||||
|
||||
if ($disable || $enable) {
|
||||
$url = new moodle_url('message.php');
|
||||
redirect($url);
|
||||
}
|
||||
// Page settings
|
||||
$PAGE->set_context(get_context_instance(CONTEXT_SYSTEM));
|
||||
|
||||
// Grab the renderer
|
||||
$renderer = $PAGE->get_renderer('core', 'message');
|
||||
|
||||
// Display the manage message outputs interface
|
||||
$processors = get_message_processors();
|
||||
$messageoutputs = $renderer->manage_messageoutputs($processors);
|
||||
|
||||
// Display the page
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('managemessageoutputs', 'message'));
|
||||
echo $messageoutputs;
|
||||
echo $OUTPUT->footer();
|
220
admin/qtypes.php
220
admin/qtypes.php
@ -1,25 +1,51 @@
|
||||
<?php
|
||||
// Allows the admin to manage question types.
|
||||
|
||||
require_once(dirname(__FILE__) . '/../config.php');
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
require_once($CFG->libdir . '/tablelib.php');
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/// Check permissions.
|
||||
require_login();
|
||||
$systemcontext = get_context_instance(CONTEXT_SYSTEM);
|
||||
require_capability('moodle/question:config', $systemcontext);
|
||||
$canviewreports = has_capability('report/questioninstances:view', $systemcontext);
|
||||
/**
|
||||
* Allows the admin to manage question types.
|
||||
*
|
||||
* @package moodlecore
|
||||
* @subpackage questionbank
|
||||
* @copyright 2008 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
admin_externalpage_setup('manageqtypes');
|
||||
|
||||
/// Get some data we will need - question counts and which types are needed.
|
||||
$counts = $DB->get_records_sql("
|
||||
require_once(dirname(__FILE__) . '/../config.php');
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
require_once($CFG->libdir . '/tablelib.php');
|
||||
|
||||
// Check permissions.
|
||||
require_login();
|
||||
$systemcontext = get_context_instance(CONTEXT_SYSTEM);
|
||||
require_capability('moodle/question:config', $systemcontext);
|
||||
$canviewreports = has_capability('report/questioninstances:view', $systemcontext);
|
||||
|
||||
admin_externalpage_setup('manageqtypes');
|
||||
|
||||
$qtypes = question_bank::get_all_qtypes();
|
||||
|
||||
// Get some data we will need - question counts and which types are needed.
|
||||
$counts = $DB->get_records_sql("
|
||||
SELECT qtype, COUNT(1) as numquestions, SUM(hidden) as numhidden
|
||||
FROM {question} GROUP BY qtype", array());
|
||||
$needed = array();
|
||||
foreach ($QTYPES as $qtypename => $qtype) {
|
||||
$needed = array();
|
||||
foreach ($qtypes as $qtypename => $qtype) {
|
||||
if (!isset($counts[$qtypename])) {
|
||||
$counts[$qtypename] = new stdClass;
|
||||
$counts[$qtypename]->numquestions = 0;
|
||||
@ -27,104 +53,104 @@
|
||||
}
|
||||
$needed[$qtypename] = $counts[$qtypename]->numquestions > 0;
|
||||
$counts[$qtypename]->numquestions -= $counts[$qtypename]->numhidden;
|
||||
}
|
||||
$needed['missingtype'] = true; // The system needs the missing question type.
|
||||
foreach ($QTYPES as $qtypename => $qtype) {
|
||||
}
|
||||
$needed['missingtype'] = true; // The system needs the missing question type.
|
||||
foreach ($qtypes as $qtypename => $qtype) {
|
||||
foreach ($qtype->requires_qtypes() as $reqtype) {
|
||||
$needed[$reqtype] = true;
|
||||
}
|
||||
}
|
||||
foreach ($counts as $qtypename => $count) {
|
||||
if (!isset($QTYPES[$qtypename])) {
|
||||
}
|
||||
foreach ($counts as $qtypename => $count) {
|
||||
if (!isset($qtypes[$qtypename])) {
|
||||
$counts['missingtype']->numquestions += $count->numquestions - $count->numhidden;
|
||||
$counts['missingtype']->numhidden += $count->numhidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Work of the correct sort order.
|
||||
$config = get_config('question');
|
||||
$sortedqtypes = array();
|
||||
foreach ($QTYPES as $qtypename => $qtype) {
|
||||
// Work of the correct sort order.
|
||||
$config = get_config('question');
|
||||
$sortedqtypes = array();
|
||||
foreach ($qtypes as $qtypename => $qtype) {
|
||||
$sortedqtypes[$qtypename] = $qtype->local_name();
|
||||
}
|
||||
$sortedqtypes = question_sort_qtype_array($sortedqtypes, $config);
|
||||
}
|
||||
$sortedqtypes = question_bank::sort_qtype_array($sortedqtypes, $config);
|
||||
|
||||
/// Process actions ============================================================
|
||||
// Process actions ============================================================
|
||||
|
||||
// Disable.
|
||||
if (($disable = optional_param('disable', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($QTYPES[$disable])) {
|
||||
print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $disable);
|
||||
// Disable.
|
||||
if (($disable = optional_param('disable', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($qtypes[$disable])) {
|
||||
print_error('unknownquestiontype', 'question', new moodle_url('/admin/qtypes.php'), $disable);
|
||||
}
|
||||
|
||||
set_config($disable . '_disabled', 1, 'question');
|
||||
redirect(admin_url('qtypes.php'));
|
||||
}
|
||||
|
||||
// Enable.
|
||||
if (($enable = optional_param('enable', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($qtypes[$enable])) {
|
||||
print_error('unknownquestiontype', 'question', new moodle_url('/admin/qtypes.php'), $enable);
|
||||
}
|
||||
|
||||
// Enable.
|
||||
if (($enable = optional_param('enable', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($QTYPES[$enable])) {
|
||||
print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $enable);
|
||||
}
|
||||
|
||||
if (!$QTYPES[$enable]->menu_name()) {
|
||||
print_error('cannotenable', 'question', admin_url('qtypes.php'), $enable);
|
||||
if (!$qtypes[$enable]->menu_name()) {
|
||||
print_error('cannotenable', 'question', new moodle_url('/admin/qtypes.php'), $enable);
|
||||
}
|
||||
|
||||
unset_config($enable . '_disabled', 'question');
|
||||
redirect(admin_url('qtypes.php'));
|
||||
}
|
||||
redirect(new moodle_url('/admin/qtypes.php'));
|
||||
}
|
||||
|
||||
// Move up in order.
|
||||
if (($up = optional_param('up', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($QTYPES[$up])) {
|
||||
print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $up);
|
||||
// Move up in order.
|
||||
if (($up = optional_param('up', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($qtypes[$up])) {
|
||||
print_error('unknownquestiontype', 'question', new moodle_url('/admin/qtypes.php'), $up);
|
||||
}
|
||||
|
||||
$neworder = question_reorder_qtypes($sortedqtypes, $up, -1);
|
||||
question_save_qtype_order($neworder, $config);
|
||||
redirect(admin_url('qtypes.php'));
|
||||
}
|
||||
redirect(new moodle_url('/admin/qtypes.php'));
|
||||
}
|
||||
|
||||
// Move down in order.
|
||||
if (($down = optional_param('down', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($QTYPES[$down])) {
|
||||
// Move down in order.
|
||||
if (($down = optional_param('down', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($qtypes[$down])) {
|
||||
print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $down);
|
||||
}
|
||||
|
||||
$neworder = question_reorder_qtypes($sortedqtypes, $down, +1);
|
||||
question_save_qtype_order($neworder, $config);
|
||||
redirect(admin_url('qtypes.php'));
|
||||
}
|
||||
redirect(new moodle_url('/admin/qtypes.php'));
|
||||
}
|
||||
|
||||
// Delete.
|
||||
if (($delete = optional_param('delete', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
// Delete.
|
||||
if (($delete = optional_param('delete', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
// Check it is OK to delete this question type.
|
||||
if ($delete == 'missingtype') {
|
||||
print_error('cannotdeletemissingqtype', 'admin', admin_url('qtypes.php'));
|
||||
print_error('cannotdeletemissingqtype', 'admin', new moodle_url('/admin/qtypes.php'));
|
||||
}
|
||||
|
||||
if (!isset($QTYPES[$delete])) {
|
||||
print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $delete);
|
||||
if (!isset($qtypes[$delete])) {
|
||||
print_error('unknownquestiontype', 'question', new moodle_url('/admin/qtypes.php'), $delete);
|
||||
}
|
||||
|
||||
$qtypename = $QTYPES[$delete]->local_name();
|
||||
$qtypename = $qtypes[$delete]->local_name();
|
||||
if ($counts[$delete]->numquestions + $counts[$delete]->numhidden > 0) {
|
||||
print_error('cannotdeleteqtypeinuse', 'admin', admin_url('qtypes.php'), $qtypename);
|
||||
print_error('cannotdeleteqtypeinuse', 'admin', new moodle_url('/admin/qtypes.php'), $qtypename);
|
||||
}
|
||||
|
||||
if ($needed[$delete] > 0) {
|
||||
print_error('cannotdeleteqtypeneeded', 'admin', admin_url('qtypes.php'), $qtypename);
|
||||
print_error('cannotdeleteqtypeneeded', 'admin', new moodle_url('/admin/qtypes.php'), $qtypename);
|
||||
}
|
||||
|
||||
// If not yet confirmed, display a confirmation message.
|
||||
if (!optional_param('confirm', '', PARAM_BOOL)) {
|
||||
$qtypename = $QTYPES[$delete]->local_name();
|
||||
$qtypename = $qtypes[$delete]->local_name();
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('deleteqtypeareyousure', 'admin', $qtypename));
|
||||
echo $OUTPUT->confirm(get_string('deleteqtypeareyousuremessage', 'admin', $qtypename),
|
||||
admin_url('qtypes.php?delete=' . $delete . '&confirm=1'),
|
||||
admin_url('qtypes.php'));
|
||||
new moodle_url('/admin/qtypes.php', array('delete' => $delete, 'confirm' => 1)),
|
||||
new moodle_url('/admin/qtypes.php'));
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
}
|
||||
@ -141,40 +167,41 @@
|
||||
unset_config($delete . '_sortorder', 'question');
|
||||
|
||||
// Then the tables themselves
|
||||
drop_plugin_tables($delete, $QTYPES[$delete]->plugin_dir() . '/db/install.xml', false);
|
||||
drop_plugin_tables($delete, $qtypes[$delete]->plugin_dir() . '/db/install.xml', false);
|
||||
|
||||
// Remove event handlers and dequeue pending events
|
||||
events_uninstall('qtype/' . $delete);
|
||||
|
||||
$a->qtype = $qtypename;
|
||||
$a->directory = $QTYPES[$delete]->plugin_dir();
|
||||
$a->directory = $qtypes[$delete]->plugin_dir();
|
||||
echo $OUTPUT->box(get_string('qtypedeletefiles', 'admin', $a), 'generalbox', 'notice');
|
||||
echo $OUTPUT->continue_button(admin_url('qtypes.php'));
|
||||
echo $OUTPUT->continue_button(new moodle_url('/admin/qtypes.php'));
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// End of process actions ==================================================
|
||||
// End of process actions ==================================================
|
||||
|
||||
/// Print the page heading.
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('manageqtypes', 'admin'));
|
||||
// Print the page heading.
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('manageqtypes', 'admin'));
|
||||
|
||||
/// Set up the table.
|
||||
$table = new flexible_table('qtypeadmintable');
|
||||
$table->define_columns(array('questiontype', 'numquestions', 'version', 'requires',
|
||||
// Set up the table.
|
||||
$table = new flexible_table('qtypeadmintable');
|
||||
$table->define_baseurl(new moodle_url('/admin/qtypes.php'));
|
||||
$table->define_columns(array('questiontype', 'numquestions', 'version', 'requires',
|
||||
'availableto', 'delete', 'settings'));
|
||||
$table->define_headers(array(get_string('questiontype', 'admin'), get_string('numquestions', 'admin'),
|
||||
$table->define_headers(array(get_string('questiontype', 'admin'), get_string('numquestions', 'admin'),
|
||||
get_string('version'), get_string('requires', 'admin'), get_string('availableq', 'question'),
|
||||
get_string('delete'), get_string('settings')));
|
||||
$table->set_attribute('id', 'qtypes');
|
||||
$table->set_attribute('class', 'generaltable generalbox boxaligncenter boxwidthwide');
|
||||
$table->setup();
|
||||
$table->set_attribute('id', 'qtypes');
|
||||
$table->set_attribute('class', 'generaltable generalbox boxaligncenter boxwidthwide');
|
||||
$table->setup();
|
||||
|
||||
/// Add a row for each question type.
|
||||
$createabletypes = question_type_menu();
|
||||
foreach ($sortedqtypes as $qtypename => $localname) {
|
||||
$qtype = $QTYPES[$qtypename];
|
||||
// Add a row for each question type.
|
||||
$createabletypes = question_bank::get_creatable_qtypes();
|
||||
foreach ($sortedqtypes as $qtypename => $localname) {
|
||||
$qtype = $qtypes[$qtypename];
|
||||
$row = array();
|
||||
|
||||
// Question icon and name.
|
||||
@ -191,7 +218,7 @@
|
||||
$strcount = $counts[$qtypename]->numquestions;
|
||||
}
|
||||
if ($canviewreports) {
|
||||
$row[] = '<a href="' . admin_url('/report/questioninstances/index.php?qtype=' . $qtypename) .
|
||||
$row[] = '<a href="' . new moodle_url('/admin/report/questioninstances/index.php', array('qtype' => $qtypename)) .
|
||||
'" title="' . get_string('showdetails', 'admin') . '">' . $strcount . '</a>';
|
||||
} else {
|
||||
$strcount;
|
||||
@ -213,7 +240,7 @@
|
||||
$strtypes = array();
|
||||
if (!empty($requiredtypes)) {
|
||||
foreach ($requiredtypes as $required) {
|
||||
$strtypes[] = $QTYPES[$required]->local_name();
|
||||
$strtypes[] = $qtypes[$required]->local_name();
|
||||
}
|
||||
$row[] = implode(', ', $strtypes);
|
||||
} else {
|
||||
@ -241,8 +268,8 @@
|
||||
if ($needed[$qtypename]) {
|
||||
$row[] = '';
|
||||
} else {
|
||||
$row[] = '<a href="' . admin_url('qtypes.php?delete=' . $qtypename .
|
||||
'&sesskey=' . sesskey()) . '" title="' .
|
||||
$row[] = '<a href="' . new moodle_url('/admin/qtypes.php', array('delete' => $qtypename,
|
||||
'sesskey' => sesskey())) . '" title="' .
|
||||
get_string('uninstallqtype', 'admin') . '">' . get_string('delete') . '</a>';
|
||||
}
|
||||
|
||||
@ -252,24 +279,19 @@
|
||||
$row[] = '<a href="' . $settings->url .
|
||||
'">' . get_string('settings') . '</a>';
|
||||
} else if ($settings instanceof admin_settingpage) {
|
||||
$row[] = '<a href="' . admin_url('settings.php?section=qtypesetting' . $qtypename) .
|
||||
$row[] = '<a href="' . new moodle_url('/admin/settings.php', array('section' => 'qtypesetting' . $qtypename)) .
|
||||
'">' . get_string('settings') . '</a>';
|
||||
} else {
|
||||
$row[] = '';
|
||||
}
|
||||
|
||||
$table->add_data($row, $rowclass);
|
||||
}
|
||||
|
||||
$table->finish_output();
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
function admin_url($endbit) {
|
||||
global $CFG;
|
||||
return $CFG->wwwroot . '/' . $CFG->admin . '/' . $endbit;
|
||||
}
|
||||
|
||||
$table->finish_output();
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
function enable_disable_button($qtypename, $createable) {
|
||||
if ($createable) {
|
||||
return icon_html('disable', $qtypename, 'i/hide', get_string('enabled', 'question'), get_string('disable'));
|
||||
@ -283,7 +305,7 @@ function icon_html($action, $qtypename, $icon, $alt, $tip) {
|
||||
if ($tip) {
|
||||
$tip = 'title="' . $tip . '" ';
|
||||
}
|
||||
$html = ' <form action="' . admin_url('qtypes.php') . '" method="post"><div>';
|
||||
$html = ' <form action="' . new moodle_url('/admin/qtypes.php') . '" method="post"><div>';
|
||||
$html .= '<input type="hidden" name="sesskey" value="' . sesskey() . '" />';
|
||||
$html .= '<input type="image" name="' . $action . '" value="' . $qtypename .
|
||||
'" src="' . $OUTPUT->pix_url($icon) . '" alt="' . $alt . '" ' . $tip . '/>';
|
||||
|
@ -22,8 +22,9 @@ echo $OUTPUT->header();
|
||||
add_to_log(SITEID, "admin", "report questioninstances", "report/questioninstances/index.php?qtype=$requestedqtype", $requestedqtype);
|
||||
|
||||
// Prepare the list of capabilities to choose from
|
||||
$qtypes = question_bank::get_all_qtypes();
|
||||
$qtypechoices = array();
|
||||
foreach ($QTYPES as $qtype) {
|
||||
foreach ($qtypes as $qtype) {
|
||||
$qtypechoices[$qtype->name()] = $qtype->local_name();
|
||||
}
|
||||
|
||||
@ -45,7 +46,7 @@ if ($requestedqtype) {
|
||||
|
||||
// Work out the bits needed for the SQL WHERE clauses.
|
||||
if ($requestedqtype == 'missingtype') {
|
||||
$othertypes = array_keys($QTYPES);
|
||||
$othertypes = array_keys($qtypes);
|
||||
$key = array_search('missingtype', $othertypes);
|
||||
unset($othertypes[$key]);
|
||||
list($sqlqtypetest, $params) = $DB->get_in_or_equal($othertypes, SQL_PARAMS_QM, '', false);
|
||||
@ -58,7 +59,8 @@ if ($requestedqtype) {
|
||||
} else {
|
||||
$sqlqtypetest = 'WHERE qtype = ?';
|
||||
$params = array($requestedqtype);
|
||||
$title = get_string('reportforqtype', 'report_questioninstances', $QTYPES[$requestedqtype]->local_name());
|
||||
$title = get_string('reportforqtype', 'report_questioninstances',
|
||||
question_bank::get_qtype($requestedqtype)->local_name());
|
||||
}
|
||||
|
||||
// Get the question counts, and all the context information, for each
|
||||
|
@ -18,6 +18,8 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$temp->add(new admin_setting_configcheckbox('allowuserblockhiding', get_string('allowuserblockhiding', 'admin'), get_string('configallowuserblockhiding', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('allowblockstodock', get_string('allowblockstodock', 'admin'), get_string('configallowblockstodock', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configtextarea('custommenuitems', get_string('custommenuitems', 'admin'), get_string('configcustommenuitems', 'admin'), '', PARAM_TEXT, '50', '10'));
|
||||
$temp->add(new admin_setting_configcheckbox('enabledevicedetection', get_string('enabledevicedetection', 'admin'), get_string('configenabledevicedetection', 'admin'), 1));
|
||||
$temp->add(new admin_setting_devicedetectregex('devicedetectregex', get_string('devicedetectregex', 'admin'), get_string('devicedetectregex_desc', 'admin'), ''));
|
||||
$ADMIN->add('themes', $temp);
|
||||
$ADMIN->add('themes', new admin_externalpage('themeselector', get_string('themeselector','admin'), $CFG->wwwroot . '/theme/index.php'));
|
||||
|
||||
|
@ -46,6 +46,27 @@ if ($hassiteconfig) {
|
||||
}
|
||||
}
|
||||
|
||||
// message outputs
|
||||
$ADMIN->add('modules', new admin_category('messageoutputs', get_string('messageoutputs', 'message')));
|
||||
$ADMIN->add('messageoutputs', new admin_page_managemessageoutputs());
|
||||
$ADMIN->add('messageoutputs', new admin_page_defaultmessageoutputs());
|
||||
require_once($CFG->dirroot.'/message/lib.php');
|
||||
$processors = get_message_processors();
|
||||
foreach ($processors as $processor) {
|
||||
$processorname = $processor->name;
|
||||
if (!$processor->available) {
|
||||
continue;
|
||||
}
|
||||
if ($processor->hassettings) {
|
||||
$strprocessorname = get_string('pluginname', 'message_'.$processorname);
|
||||
$settings = new admin_settingpage('messagesetting'.$processorname, $strprocessorname, 'moodle/site:config', !$processor->enabled);
|
||||
include($CFG->dirroot.'/message/output/'.$processor->name.'/settings.php');
|
||||
if ($settings) {
|
||||
$ADMIN->add('messageoutputs', $settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// authentication plugins
|
||||
$ADMIN->add('modules', new admin_category('authsettings', get_string('authentication', 'admin')));
|
||||
|
||||
@ -324,6 +345,9 @@ if ($hassiteconfig) {
|
||||
$ADMIN->add('webservicesettings', $temp);
|
||||
/// manage service
|
||||
$temp = new admin_settingpage('externalservices', get_string('externalservices', 'webservice'));
|
||||
$enablemobiledocurl = new moodle_url(get_docs_url('Enable_mobile_web_services'));
|
||||
$enablemobiledoclink = html_writer::link($enablemobiledocurl, get_string('documentation'));
|
||||
$temp->add(new admin_setting_enablemobileservice('enablemobilewebservice', get_string('enablemobilewebservice', 'admin'), get_string('configenablemobilewebservice', 'admin', $enablemobiledoclink), 0));
|
||||
$temp->add(new admin_setting_heading('manageserviceshelpexplaination', get_string('information', 'webservice'), get_string('servicehelpexplanation', 'webservice')));
|
||||
$temp->add(new admin_setting_manageexternalservices());
|
||||
$ADMIN->add('webservicesettings', $temp);
|
||||
|
@ -17,46 +17,8 @@ $ADMIN->add('server', $temp);
|
||||
|
||||
|
||||
|
||||
// "email" settingpage
|
||||
$temp = new admin_settingpage('mail', get_string('mail','admin'));
|
||||
$temp->add(new admin_setting_configtext('smtphosts', get_string('smtphosts', 'admin'), get_string('configsmtphosts', 'admin'), '', PARAM_RAW));
|
||||
$temp->add(new admin_setting_configtext('smtpuser', get_string('smtpuser', 'admin'), get_string('configsmtpuser', 'admin'), '', PARAM_NOTAGS));
|
||||
$temp->add(new admin_setting_configpasswordunmask('smtppass', get_string('smtppass', 'admin'), get_string('configsmtpuser', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configtext('smtpmaxbulk', get_string('smtpmaxbulk', 'admin'), get_string('configsmtpmaxbulk', 'admin'), 1, PARAM_INT));
|
||||
$temp->add(new admin_setting_configtext('noreplyaddress', get_string('noreplyaddress', 'admin'), get_string('confignoreplyaddress', 'admin'), 'noreply@' . get_host_from_url($CFG->wwwroot), PARAM_NOTAGS));
|
||||
$temp->add(new admin_setting_configselect('digestmailtime', get_string('digestmailtime', 'admin'), get_string('configdigestmailtime', 'admin'), 17, array('00' => '00',
|
||||
'01' => '01',
|
||||
'02' => '02',
|
||||
'03' => '03',
|
||||
'04' => '04',
|
||||
'05' => '05',
|
||||
'06' => '06',
|
||||
'07' => '07',
|
||||
'08' => '08',
|
||||
'09' => '09',
|
||||
'10' => '10',
|
||||
'11' => '11',
|
||||
'12' => '12',
|
||||
'13' => '13',
|
||||
'14' => '14',
|
||||
'15' => '15',
|
||||
'16' => '16',
|
||||
'17' => '17',
|
||||
'18' => '18',
|
||||
'19' => '19',
|
||||
'20' => '20',
|
||||
'21' => '21',
|
||||
'22' => '22',
|
||||
'23' => '23')));
|
||||
$charsets = get_list_of_charsets();
|
||||
unset($charsets['UTF-8']); // not needed here
|
||||
$options = array();
|
||||
$options['0'] = 'UTF-8';
|
||||
$options = array_merge($options, $charsets);
|
||||
$temp->add(new admin_setting_configselect('sitemailcharset', get_string('sitemailcharset', 'admin'), get_string('configsitemailcharset','admin'), '0', $options));
|
||||
$temp->add(new admin_setting_configcheckbox('allowusermailcharset', get_string('allowusermailcharset', 'admin'), get_string('configallowusermailcharset', 'admin'), 0));
|
||||
$options = array('LF'=>'LF', 'CRLF'=>'CRLF');
|
||||
$temp->add(new admin_setting_configselect('mailnewline', get_string('mailnewline', 'admin'), get_string('configmailnewline','admin'), 'LF', $options));
|
||||
// "supportcontact" settingpage
|
||||
$temp = new admin_settingpage('supportcontact', get_string('supportcontact','admin'));
|
||||
if (isloggedin()) {
|
||||
global $USER;
|
||||
$primaryadminemail = $USER->email;
|
||||
@ -73,17 +35,6 @@ $temp->add(new admin_setting_configtext('supportpage', get_string('supportpage',
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
|
||||
// Jabber settingpage
|
||||
$temp = new admin_settingpage('jabber', get_string('jabber', 'admin'));
|
||||
$temp->add(new admin_setting_configtext('jabberhost', get_string('jabberhost', 'admin'), get_string('configjabberhost', 'admin'), '', PARAM_RAW));
|
||||
$temp->add(new admin_setting_configtext('jabberserver', get_string('jabberserver', 'admin'), get_string('configjabberserver', 'admin'), '', PARAM_RAW));
|
||||
$temp->add(new admin_setting_configtext('jabberusername', get_string('jabberusername', 'admin'), get_string('configjabberusername', 'admin'), '', PARAM_RAW));
|
||||
$temp->add(new admin_setting_configpasswordunmask('jabberpassword', get_string('jabberpassword', 'admin'), get_string('configjabberpassword', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configtext('jabberport', get_string('jabberport', 'admin'), get_string('configjabberport', 'admin'), 5222, PARAM_INT));
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
|
||||
|
||||
// "sessionhandling" settingpage
|
||||
$temp = new admin_settingpage('sessionhandling', get_string('sessionhandling', 'admin'));
|
||||
$temp->add(new admin_setting_configcheckbox('dbsessions', get_string('dbsessions', 'admin'), get_string('configdbsessions', 'admin'), 1));
|
||||
|
@ -111,8 +111,7 @@ abstract class backup_qtype_plugin extends backup_plugin {
|
||||
// Define the elements
|
||||
$options = new backup_nested_element('numerical_options');
|
||||
$option = new backup_nested_element('numerical_option', array('id'), array(
|
||||
'instructions', 'instructionsformat', 'showunits', 'unitsleft',
|
||||
'unitgradingtype', 'unitpenalty'));
|
||||
'showunits', 'unitsleft', 'unitgradingtype', 'unitpenalty'));
|
||||
|
||||
// Build the tree
|
||||
$element->add_child($options);
|
||||
|
@ -174,78 +174,76 @@ abstract class backup_questions_activity_structure_step extends backup_activity_
|
||||
|
||||
/**
|
||||
* Attach to $element (usually attempts) the needed backup structures
|
||||
* for question_states for a given question_attempt
|
||||
* for question_usages and all the associated data.
|
||||
*/
|
||||
protected function add_question_attempts_states($element, $questionattemptname) {
|
||||
protected function add_question_usages($element, $usageidname) {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/question/engine/lib.php');
|
||||
|
||||
// Check $element is one nested_backup_element
|
||||
if (! $element instanceof backup_nested_element) {
|
||||
throw new backup_step_exception('question_states_bad_parent_element', $element);
|
||||
}
|
||||
// Check that the $questionattemptname is final element in $element
|
||||
if (! $element->get_final_element($questionattemptname)) {
|
||||
throw new backup_step_exception('question_states_bad_question_attempt_element', $questionattemptname);
|
||||
if (! $element->get_final_element($usageidname)) {
|
||||
throw new backup_step_exception('question_states_bad_question_attempt_element', $usageidname);
|
||||
}
|
||||
|
||||
// TODO: Some day we should stop these "encrypted" state->answers and
|
||||
// TODO: delegate to qtypes plugin to proper XML writting the needed info on each question
|
||||
$quba = new backup_nested_element('question_usage', array('id'),
|
||||
array('component', 'preferredbehaviour'));
|
||||
|
||||
// TODO: Should be doing here some introspection in the "answer" element, based on qtype,
|
||||
// TODO: to know which real questions are being used (for randoms and other qtypes...)
|
||||
// TODO: Not needed if consistency is guaranteed, but it isn't right now :-(
|
||||
$qas = new backup_nested_element('question_attempts');
|
||||
$qa = new backup_nested_element('question_attempt', array('id'), array(
|
||||
'slot', 'behaviour', 'questionid', 'maxmark', 'minfraction',
|
||||
'flagged', 'questionsummary', 'rightanswer', 'responsesummary',
|
||||
'timemodified'));
|
||||
|
||||
// Define the elements
|
||||
$states = new backup_nested_element('states');
|
||||
$state = new backup_nested_element('state', array('id'), array(
|
||||
'question', 'seq_number', 'answer', 'timestamp',
|
||||
'event', 'grade', 'raw_grade', 'penalty'));
|
||||
$steps = new backup_nested_element('steps');
|
||||
$step = new backup_nested_element('step', array('id'), array(
|
||||
'sequencenumber', 'state', 'fraction', 'timecreated', 'userid'));
|
||||
|
||||
$response = new backup_nested_element('response');
|
||||
$variable = new backup_nested_element('variable', null, array('name', 'value'));
|
||||
|
||||
// Build the tree
|
||||
$element->add_child($states);
|
||||
$states->add_child($state);
|
||||
$element->add_child($quba);
|
||||
$quba->add_child($qas);
|
||||
$qas->add_child($qa);
|
||||
$qa->add_child($steps);
|
||||
$steps->add_child($step);
|
||||
$step->add_child($response);
|
||||
$response->add_child($variable);
|
||||
|
||||
// Set the sources
|
||||
$state->set_source_table('question_states', array('attempt' => '../../' . $questionattemptname));
|
||||
$quba->set_source_table('question_usages',
|
||||
array('id' => '../' . $usageidname));
|
||||
$qa->set_source_sql('
|
||||
SELECT *
|
||||
FROM {question_attempts}
|
||||
WHERE questionusageid = :questionusageid
|
||||
ORDER BY slot',
|
||||
array('questionusageid' => backup::VAR_PARENTID));
|
||||
$step->set_source_sql('
|
||||
SELECT *
|
||||
FROM {question_attempt_steps}
|
||||
WHERE questionattemptid = :questionattemptid
|
||||
ORDER BY sequencenumber',
|
||||
array('questionattemptid' => backup::VAR_PARENTID));
|
||||
$variable->set_source_table('question_attempt_step_data',
|
||||
array('attemptstepid' => backup::VAR_PARENTID));
|
||||
|
||||
// Annotate ids
|
||||
$state->annotate_ids('question', 'question');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach to $element (usually attempts) the needed backup structures
|
||||
* for question_sessions for a given question_attempt
|
||||
*/
|
||||
protected function add_question_attempts_sessions($element, $questionattemptname) {
|
||||
// Check $element is one nested_backup_element
|
||||
if (! $element instanceof backup_nested_element) {
|
||||
throw new backup_step_exception('question_sessions_bad_parent_element', $element);
|
||||
}
|
||||
// Check that the $questionattemptname is final element in $element
|
||||
if (! $element->get_final_element($questionattemptname)) {
|
||||
throw new backup_step_exception('question_sessions_bad_question_attempt_element', $questionattemptname);
|
||||
}
|
||||
|
||||
// Define the elements
|
||||
$sessions = new backup_nested_element('sessions');
|
||||
$session = new backup_nested_element('session', array('id'), array(
|
||||
'questionid', 'newest', 'newgraded', 'sumpenalty',
|
||||
'manualcomment', 'manualcommentformat', 'flagged'));
|
||||
|
||||
// Build the tree
|
||||
$element->add_child($sessions);
|
||||
$sessions->add_child($session);
|
||||
|
||||
// Set the sources
|
||||
$session->set_source_table('question_sessions', array('attemptid' => '../../' . $questionattemptname));
|
||||
|
||||
// Annotate ids
|
||||
$session->annotate_ids('question', 'questionid');
|
||||
$qa->annotate_ids('question', 'questionid');
|
||||
$step->annotate_ids('user', 'userid');
|
||||
|
||||
// Annotate files
|
||||
// Note: question_sessions haven't files associated. On purpose manualcomment is lacking
|
||||
// support for them, so we don't need to annotated them here.
|
||||
$fileareas = question_engine::get_all_response_file_areas();
|
||||
foreach ($fileareas as $filearea) {
|
||||
$step->annotate_files('question', $filearea, 'id');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* backup structure step in charge of calculating the categories to be
|
||||
* included in backup, based in the context being backuped (module/course)
|
||||
@ -1670,19 +1668,25 @@ class backup_questions_structure_step extends backup_structure_step {
|
||||
|
||||
$question = new backup_nested_element('question', array('id'), array(
|
||||
'parent', 'name', 'questiontext', 'questiontextformat',
|
||||
'generalfeedback', 'generalfeedbackformat', 'defaultgrade', 'penalty',
|
||||
'generalfeedback', 'generalfeedbackformat', 'defaultmark', 'penalty',
|
||||
'qtype', 'length', 'stamp', 'version',
|
||||
'hidden', 'timecreated', 'timemodified', 'createdby', 'modifiedby'));
|
||||
|
||||
// attach qtype plugin structure to $question element, only one allowed
|
||||
$this->add_plugin_structure('qtype', $question, false);
|
||||
|
||||
$qhints = new backup_nested_element('question_hints');
|
||||
|
||||
$qhint = new backup_nested_element('question_hint', array('id'), array(
|
||||
'hint', 'hintformat', 'shownumcorrect', 'clearwrong', 'options'));
|
||||
|
||||
// Build the tree
|
||||
|
||||
$qcategories->add_child($qcategory);
|
||||
$qcategory->add_child($questions);
|
||||
|
||||
$questions->add_child($question);
|
||||
$question->add_child($qhints);
|
||||
$qhints->add_child($qhint);
|
||||
|
||||
// Define the sources
|
||||
|
||||
@ -1696,6 +1700,13 @@ class backup_questions_structure_step extends backup_structure_step {
|
||||
|
||||
$question->set_source_table('question', array('category' => backup::VAR_PARENTID));
|
||||
|
||||
$qhint->set_source_sql('
|
||||
SELECT *
|
||||
FROM {question_hints}
|
||||
WHERE questionid = :questionid
|
||||
ORDER BY id',
|
||||
array('questionid' => backup::VAR_PARENTID));
|
||||
|
||||
// don't need to annotate ids nor files
|
||||
// (already done by {@link backup_annotate_all_question_files}
|
||||
|
||||
|
@ -115,6 +115,23 @@ abstract class restore_qtype_plugin extends restore_plugin {
|
||||
$newquestionid = $this->get_new_parentid('question');
|
||||
$questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false;
|
||||
|
||||
// In the past, there were some sloppily rounded fractions around. Fix them up.
|
||||
$changes = array(
|
||||
'-0.66666' => '-0.6666667',
|
||||
'-0.33333' => '-0.3333333',
|
||||
'-0.16666' => '-0.1666667',
|
||||
'-0.142857' => '-0.1428571',
|
||||
'0.11111' => '0.1111111',
|
||||
'0.142857' => '0.1428571',
|
||||
'0.16666' => '0.1666667',
|
||||
'0.33333' => '0.3333333',
|
||||
'0.333333' => '0.3333333',
|
||||
'0.66666' => '0.6666667',
|
||||
);
|
||||
if (array_key_exists($data->fraction, $changes)) {
|
||||
$data->fraction = $changes[$data->fraction];
|
||||
}
|
||||
|
||||
// If the question has been created by restore, we need to create its question_answers too
|
||||
if ($questioncreated) {
|
||||
// Adjust some columns
|
||||
@ -298,11 +315,14 @@ abstract class restore_qtype_plugin extends restore_plugin {
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode one question_states for this qtype (default impl)
|
||||
* Do any re-coding necessary in the student response.
|
||||
* @param int $questionid the new id of the question
|
||||
* @param int $sequencenumber of the step within the qusetion attempt.
|
||||
* @param array the response data from the backup.
|
||||
* @return array the recoded response.
|
||||
*/
|
||||
public function recode_state_answer($state) {
|
||||
// By default, return answer unmodified, qtypes needing recode will override this
|
||||
return $state->answer;
|
||||
public function recode_response($questionid, $sequencenumber, array $response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2310,6 +2310,17 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
// we have loaded qcatids there for all parsed questions
|
||||
$data->category = $this->get_mappingid('question_category', $questionmapping->parentitemid);
|
||||
|
||||
// In the past, there were some very sloppy values of penalty. Fix them.
|
||||
if ($data->penalty >= 0.33 && $data->penalty <= 0.34) {
|
||||
$data->penalty = 0.3333333;
|
||||
}
|
||||
if ($data->penalty >= 0.66 && $data->penalty <= 0.67) {
|
||||
$data->penalty = 0.6666667;
|
||||
}
|
||||
if ($data->penalty >= 1) {
|
||||
$data->penalty = 1;
|
||||
}
|
||||
|
||||
$data->timecreated = $this->apply_date_offset($data->timecreated);
|
||||
$data->timemodified = $this->apply_date_offset($data->timemodified);
|
||||
|
||||
@ -2339,6 +2350,47 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
// step will be in charge of restoring all the question files
|
||||
}
|
||||
|
||||
protected function process_question_hint($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
// Detect if the question is created or mapped
|
||||
$oldquestionid = $this->get_old_parentid('question');
|
||||
$newquestionid = $this->get_new_parentid('question');
|
||||
$questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false;
|
||||
|
||||
// If the question has been created by restore, we need to create its question_answers too
|
||||
if ($questioncreated) {
|
||||
// Adjust some columns
|
||||
$data->questionid = $newquestionid;
|
||||
// Insert record
|
||||
$newitemid = $DB->insert_record('question_answers', $data);
|
||||
|
||||
// The question existed, we need to map the existing question_answers
|
||||
} else {
|
||||
// Look in question_answers by answertext matching
|
||||
$sql = 'SELECT id
|
||||
FROM {question_hints}
|
||||
WHERE questionid = ?
|
||||
AND ' . $DB->sql_compare_text('hint', 255) . ' = ' . $DB->sql_compare_text('?', 255);
|
||||
$params = array($newquestionid, $data->hint);
|
||||
$newitemid = $DB->get_field_sql($sql, $params);
|
||||
// If we haven't found the newitemid, something has gone really wrong, question in DB
|
||||
// is missing answers, exception
|
||||
if (!$newitemid) {
|
||||
$info = new stdClass();
|
||||
$info->filequestionid = $oldquestionid;
|
||||
$info->dbquestionid = $newquestionid;
|
||||
$info->hint = $data->hint;
|
||||
throw new restore_step_exception('error_question_hint_missing_in_db', $info);
|
||||
}
|
||||
}
|
||||
// Create mapping (we'll use this intensively when restoring question_states. And also answerfeedback files)
|
||||
$this->set_mapping('question_hint', $oldid, $newitemid);
|
||||
}
|
||||
|
||||
protected function after_execute() {
|
||||
global $DB;
|
||||
|
||||
@ -2461,6 +2513,8 @@ class restore_create_question_files extends restore_execution_step {
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answerfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'hint',
|
||||
$oldctxid, $this->task->get_userid(), 'question_hint', null, $newctxid, true);
|
||||
// Add qtype dependent files
|
||||
$components = backup_qtype_plugin::get_components_and_fileareas($question->qtype);
|
||||
foreach ($components as $component => $fileareas) {
|
||||
@ -2481,12 +2535,16 @@ class restore_create_question_files extends restore_execution_step {
|
||||
* (like the quiz module), to support qtype plugins, states and sessions
|
||||
*/
|
||||
abstract class restore_questions_activity_structure_step extends restore_activity_structure_step {
|
||||
/** @var array question_attempt->id to qtype. */
|
||||
protected $qtypes = array();
|
||||
/** @var array question_attempt->id to questionid. */
|
||||
protected $newquestionids = array();
|
||||
|
||||
/**
|
||||
* Attach below $element (usually attempts) the needed restore_path_elements
|
||||
* to restore question_states
|
||||
* to restore question_usages and all they contain.
|
||||
*/
|
||||
protected function add_question_attempts_states($element, &$paths) {
|
||||
protected function add_question_usages($element, &$paths) {
|
||||
// Check $element is restore_path_element
|
||||
if (! $element instanceof restore_path_element) {
|
||||
throw new restore_step_exception('element_must_be_restore_path_element', $element);
|
||||
@ -2495,70 +2553,114 @@ abstract class restore_questions_activity_structure_step extends restore_activit
|
||||
if (!is_array($paths)) {
|
||||
throw new restore_step_exception('paths_must_be_array', $paths);
|
||||
}
|
||||
$paths[] = new restore_path_element('question_state', $element->get_path() . '/states/state');
|
||||
$paths[] = new restore_path_element('question_usage',
|
||||
$element->get_path() . '/question_usage');
|
||||
$paths[] = new restore_path_element('question_attempt',
|
||||
$element->get_path() . '/question_usage/question_attempts/question_attempt');
|
||||
$paths[] = new restore_path_element('question_attempt_step',
|
||||
$element->get_path() . '/question_usage/question_attempts/question_attempt/steps/step',
|
||||
true);
|
||||
$paths[] = new restore_path_element('question_attempt_step_data',
|
||||
$element->get_path() . '/question_usage/question_attempts/question_attempt/steps/step/response/variable');
|
||||
|
||||
// TODO Put back code for restoring legacy 2.0 backups.
|
||||
// $paths[] = new restore_path_element('question_state', $element->get_path() . '/states/state');
|
||||
// $paths[] = new restore_path_element('question_session', $element->get_path() . '/sessions/session');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach below $element (usually attempts) the needed restore_path_elements
|
||||
* to restore question_sessions
|
||||
* Process question_usages
|
||||
*/
|
||||
protected function add_question_attempts_sessions($element, &$paths) {
|
||||
// Check $element is restore_path_element
|
||||
if (! $element instanceof restore_path_element) {
|
||||
throw new restore_step_exception('element_must_be_restore_path_element', $element);
|
||||
}
|
||||
// Check $paths is one array
|
||||
if (!is_array($paths)) {
|
||||
throw new restore_step_exception('paths_must_be_array', $paths);
|
||||
}
|
||||
$paths[] = new restore_path_element('question_session', $element->get_path() . '/sessions/session');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process question_states
|
||||
*/
|
||||
protected function process_question_state($data) {
|
||||
protected function process_question_usage($data) {
|
||||
global $DB;
|
||||
|
||||
// Clear our caches.
|
||||
$this->qtypes = array();
|
||||
$this->newquestionids = array();
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
// Get complete question mapping, we'll need info
|
||||
$question = $this->get_mapping('question', $data->question);
|
||||
|
||||
// In the quiz_attempt mapping we are storing uniqueid
|
||||
// and not id, so this gets the correct question_attempt to point to
|
||||
$data->attempt = $this->get_new_parentid('quiz_attempt');
|
||||
$data->question = $question->newitemid;
|
||||
$data->answer = $this->restore_recode_answer($data, $question->info->qtype); // Delegate recoding of answer
|
||||
$data->timestamp= $this->apply_date_offset($data->timestamp);
|
||||
|
||||
// Everything ready, insert and create mapping (needed by question_sessions)
|
||||
$newitemid = $DB->insert_record('question_states', $data);
|
||||
$this->set_mapping('question_state', $oldid, $newitemid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process question_sessions
|
||||
*/
|
||||
protected function process_question_session($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
// In the quiz_attempt mapping we are storing uniqueid
|
||||
// and not id, so this gets the correct question_attempt to point to
|
||||
$data->attemptid = $this->get_new_parentid('quiz_attempt');
|
||||
$data->questionid = $this->get_mappingid('question', $data->questionid);
|
||||
$data->newest = $this->get_mappingid('question_state', $data->newest);
|
||||
$data->newgraded = $this->get_mappingid('question_state', $data->newgraded);
|
||||
$oldcontextid = $this->get_task()->get_old_contextid();
|
||||
$data->contextid = $this->get_mappingid('context', $this->task->get_old_contextid());
|
||||
|
||||
// Everything ready, insert (no mapping needed)
|
||||
$newitemid = $DB->insert_record('question_sessions', $data);
|
||||
$newitemid = $DB->insert_record('question_usages', $data);
|
||||
|
||||
// Note: question_sessions haven't files associated. On purpose manualcomment is lacking
|
||||
// support for them, so we don't need to handle them here.
|
||||
$this->inform_new_usage_id($newitemid);
|
||||
|
||||
$this->set_mapping('question_usage', $oldid, $newitemid, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* When process_question_usage creates the new usage, it calls this method
|
||||
* to let the activity link to the new usage. For example, the quiz uses
|
||||
* this method to set quiz_attempts.uniqueid to the new usage id.
|
||||
* @param integer $newusageid
|
||||
*/
|
||||
abstract protected function inform_new_usage_id($newusageid);
|
||||
|
||||
/**
|
||||
* Process question_attempts
|
||||
*/
|
||||
protected function process_question_attempt($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
$question = $this->get_mapping('question', $data->questionid);
|
||||
|
||||
$data->questionusageid = $this->get_new_parentid('question_usage');
|
||||
$data->questionid = $question->newitemid;
|
||||
$data->timemodified = $this->apply_date_offset($data->timemodified);
|
||||
|
||||
$newitemid = $DB->insert_record('question_attempts', $data);
|
||||
|
||||
$this->set_mapping('question_attempt', $oldid, $newitemid);
|
||||
$this->qtypes[$newitemid] = $question->info->qtype;
|
||||
$this->newquestionids[$newitemid] = $data->questionid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process question_attempt_steps
|
||||
*/
|
||||
protected function process_question_attempt_step($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
// Pull out the response data.
|
||||
$response = array();
|
||||
if (!empty($data->response['variable'])) {
|
||||
foreach ($data->response['variable'] as $variable) {
|
||||
$response[$variable['name']] = $variable['value'];
|
||||
}
|
||||
}
|
||||
unset($data->response);
|
||||
|
||||
$data->questionattemptid = $this->get_new_parentid('question_attempt');
|
||||
$data->timecreated = $this->apply_date_offset($data->timecreated);
|
||||
$data->userid = $this->get_mappingid('user', $data->userid);
|
||||
|
||||
// Everything ready, insert and create mapping (needed by question_sessions)
|
||||
$newitemid = $DB->insert_record('question_attempt_steps', $data);
|
||||
$this->set_mapping('question_attempt_step', $oldid, $newitemid, true);
|
||||
|
||||
// Now process the response data.
|
||||
$qtyperestorer = $this->get_qtype_restorer($this->qtypes[$data->questionattemptid]);
|
||||
if ($qtyperestorer) {
|
||||
$response = $qtyperestorer->recode_response(
|
||||
$this->newquestionids[$data->questionattemptid],
|
||||
$data->sequencenumber, $response);
|
||||
}
|
||||
foreach ($response as $name => $value) {
|
||||
$row = new stdClass();
|
||||
$row->attemptstepid = $newitemid;
|
||||
$row->name = $name;
|
||||
$row->value = $value;
|
||||
$DB->insert_record('question_attempt_step_data', $row, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2581,25 +2683,33 @@ abstract class restore_questions_activity_structure_step extends restore_activit
|
||||
}
|
||||
|
||||
/**
|
||||
* Given one question_states record, return the answer
|
||||
* recoded pointing to all the restored stuff
|
||||
* Get the restore_qtype_plugin subclass for a specific question type.
|
||||
* @param string $qtype e.g. multichoice.
|
||||
* @return restore_qtype_plugin instance.
|
||||
*/
|
||||
public function restore_recode_answer($state, $qtype) {
|
||||
protected function get_qtype_restorer($qtype) {
|
||||
// Build one static cache to store {@link restore_qtype_plugin}
|
||||
// while we are needing them, just to save zillions of instantiations
|
||||
// or using static stuff that will break our nice API
|
||||
static $qtypeplugins = array();
|
||||
|
||||
// If we haven't the corresponding restore_qtype_plugin for current qtype
|
||||
// instantiate it and add to cache
|
||||
if (!isset($qtypeplugins[$qtype])) {
|
||||
$classname = 'restore_qtype_' . $qtype . '_plugin';
|
||||
if (class_exists($classname)) {
|
||||
$qtypeplugins[$qtype] = new $classname('qtype', $qtype, $this);
|
||||
} else {
|
||||
$qtypeplugins[$qtype] = false;
|
||||
$qtypeplugins[$qtype] = null;
|
||||
}
|
||||
}
|
||||
return !empty($qtypeplugins[$qtype]) ? $qtypeplugins[$qtype]->recode_state_answer($state) : $state->answer;
|
||||
return $qtypeplugins[$qtype];
|
||||
}
|
||||
|
||||
protected function after_execute() {
|
||||
parent::after_execute();
|
||||
|
||||
// Restore any files belonging to responses.
|
||||
foreach (question_engine::get_all_response_file_areas() as $filearea) {
|
||||
$this->add_related_files('question', $filearea, 'question_attempt_step');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,9 +43,9 @@ class moodle_enrol_external extends external_api {
|
||||
return new external_function_parameters(
|
||||
array(
|
||||
'courseid' => new external_value(PARAM_INT, 'Course id'),
|
||||
'withcapability' => new external_value(PARAM_CAPABILITY, 'User should have this capability'),
|
||||
'groupid' => new external_value(PARAM_INT, 'Group id, null means all groups'),
|
||||
'onlyactive' => new external_value(PARAM_INT, 'True means only active, false means all participants'),
|
||||
'withcapability' => new external_value(PARAM_CAPABILITY, 'User should have this capability', VALUE_DEFAULT, null),
|
||||
'groupid' => new external_value(PARAM_INT, 'Group id, null means all groups', VALUE_DEFAULT, null),
|
||||
'onlyactive' => new external_value(PARAM_INT, 'True means only active, false means all participants', VALUE_DEFAULT, 0),
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -59,12 +59,17 @@ class moodle_enrol_external extends external_api {
|
||||
* @param bool $onlyactive
|
||||
* @return array of course participants
|
||||
*/
|
||||
public static function get_enrolled_users($courseid, $withcapability, $groupid, $onlyactive) {
|
||||
global $DB;
|
||||
public static function get_enrolled_users($courseid, $withcapability = null, $groupid = null, $onlyactive = false) {
|
||||
global $DB, $CFG, $USER;
|
||||
|
||||
// Do basic automatic PARAM checks on incoming data, using params description
|
||||
// If any problems are found then exceptions are thrown with helpful error messages
|
||||
$params = self::validate_parameters(self::get_enrolled_users_parameters(), array('courseid'=>$courseid, 'withcapability'=>$withcapability, 'groupid'=>$groupid, 'onlyactive'=>$onlyactive));
|
||||
$params = self::validate_parameters(self::get_enrolled_users_parameters(), array(
|
||||
'courseid'=>$courseid,
|
||||
'withcapability'=>$withcapability,
|
||||
'groupid'=>$groupid,
|
||||
'onlyactive'=>$onlyactive)
|
||||
);
|
||||
|
||||
$coursecontext = get_context_instance(CONTEXT_COURSE, $params['courseid']);
|
||||
if ($courseid == SITEID) {
|
||||
@ -79,8 +84,7 @@ class moodle_enrol_external extends external_api {
|
||||
$exceptionparam = new stdClass();
|
||||
$exceptionparam->message = $e->getMessage();
|
||||
$exceptionparam->courseid = $params['courseid'];
|
||||
throw new moodle_exception(
|
||||
get_string('errorcoursecontextnotvalid' , 'webservice', $exceptionparam));
|
||||
throw new moodle_exception(get_string('errorcoursecontextnotvalid' , 'webservice', $exceptionparam));
|
||||
}
|
||||
|
||||
if ($courseid == SITEID) {
|
||||
@ -92,28 +96,46 @@ class moodle_enrol_external extends external_api {
|
||||
if ($withcapability) {
|
||||
require_capability('moodle/role:review', $coursecontext);
|
||||
}
|
||||
if ($groupid) {
|
||||
if (groups_is_member($groupid)) {
|
||||
if ($groupid && groups_is_member($groupid)) {
|
||||
require_capability('moodle/site:accessallgroups', $coursecontext);
|
||||
}
|
||||
}
|
||||
if ($onlyactive) {
|
||||
require_capability('moodle/course:enrolreview', $coursecontext);
|
||||
}
|
||||
|
||||
list($sql, $params) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive);
|
||||
$sql = "SELECT DISTINCT ue.userid, e.courseid
|
||||
list($sqlparams, $params) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive);
|
||||
$sql = "SELECT ue.userid, e.courseid, u.firstname, u.lastname, u.username, c.id as usercontextid
|
||||
FROM {user_enrolments} ue
|
||||
JOIN {enrol} e ON (e.id = ue.enrolid)
|
||||
WHERE e.courseid = :courseid AND ue.userid IN ($sql)";
|
||||
JOIN {user} u ON (ue.userid = u.id)
|
||||
JOIN {context} c ON (u.id = c.instanceid AND contextlevel = " . CONTEXT_USER . ")
|
||||
WHERE e.courseid = :courseid AND ue.userid IN ($sqlparams)
|
||||
GROUP BY ue.userid, e.courseid, u.firstname, u.lastname, u.username, c.id";
|
||||
$params['courseid'] = $courseid;
|
||||
|
||||
$enrolledusers = $DB->get_records_sql($sql, $params);
|
||||
|
||||
$result = array();
|
||||
$isadmin = is_siteadmin($USER);
|
||||
$canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
|
||||
foreach ($enrolledusers as $enrolleduser) {
|
||||
$result[] = array('courseid' => $enrolleduser->courseid,
|
||||
'userid' => $enrolleduser->userid);
|
||||
$profilimgurl = moodle_url::make_pluginfile_url($enrolleduser->usercontextid, 'user', 'icon', NULL, '/', 'f1');
|
||||
$profilimgurlsmall = moodle_url::make_pluginfile_url($enrolleduser->usercontextid, 'user', 'icon', NULL, '/', 'f2');
|
||||
$resultuser = array(
|
||||
'courseid' => $enrolleduser->courseid,
|
||||
'userid' => $enrolleduser->userid,
|
||||
'fullname' => fullname($enrolleduser),
|
||||
'profileimgurl' => $profilimgurl->out(false),
|
||||
'profileimgurlsmall' => $profilimgurlsmall->out(false)
|
||||
);
|
||||
// check if we can return username
|
||||
if ($isadmin) {
|
||||
$resultuser['username'] = $enrolleduser->username;
|
||||
}
|
||||
// check if we can return first and last name
|
||||
if ($isadmin or $canviewfullnames) {
|
||||
$resultuser['firstname'] = $enrolleduser->firstname;
|
||||
$resultuser['lastname'] = $enrolleduser->lastname;
|
||||
}
|
||||
$result[] = $resultuser;
|
||||
}
|
||||
|
||||
return $result;
|
||||
@ -129,12 +151,17 @@ class moodle_enrol_external extends external_api {
|
||||
array(
|
||||
'courseid' => new external_value(PARAM_INT, 'id of course'),
|
||||
'userid' => new external_value(PARAM_INT, 'id of user'),
|
||||
'firstname' => new external_value(PARAM_RAW, 'first name of user', VALUE_OPTIONAL),
|
||||
'lastname' => new external_value(PARAM_RAW, 'last name of user', VALUE_OPTIONAL),
|
||||
'fullname' => new external_value(PARAM_RAW, 'fullname of user'),
|
||||
'username' => new external_value(PARAM_RAW, 'username of user', VALUE_OPTIONAL),
|
||||
'profileimgurl' => new external_value(PARAM_URL, 'url of the profile image'),
|
||||
'profileimgurlsmall' => new external_value(PARAM_URL, 'url of the profile image (small version)')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns description of method parameters
|
||||
* @return external_function_parameters
|
||||
|
@ -51,7 +51,6 @@ $string['allowobjectembed'] = 'Allow EMBED and OBJECT tags';
|
||||
$string['allowrenames'] = 'Allow renames';
|
||||
$string['allowthemechangeonurl'] = 'Allow theme changes in the URL';
|
||||
$string['allowuserblockhiding'] = 'Allow users to hide blocks';
|
||||
$string['allowusermailcharset'] = 'Allow user to select character set';
|
||||
$string['allowuserswitchrolestheycantassign'] = 'Allow users without the assign roles capability to switch roles';
|
||||
$string['allowuserthemes'] = 'Allow user themes';
|
||||
$string['antivirus'] = 'Anti-Virus';
|
||||
@ -133,7 +132,6 @@ $string['configallowoverride2'] = 'Select which role(s) can be overridden by eac
|
||||
$string['configallowswitch'] = 'Select which roles a user may switch to, based on which roles they already have. In addition to an entry in this table, a user must also have the moodle/role:switchroles capability to be able to switch.<br />Note that it is only possible to switch to roles that have the moodle/course:view capability, and that do not have the moodle/site:doanything capability, so some columns in this table are disabled.';
|
||||
$string['configallowthemechangeonurl'] = 'If enabled, the theme can be changed by adding theme={themename} to any Moodle URL.';
|
||||
$string['configallowuserblockhiding'] = 'Do you want to allow users to hide/show side blocks throughout this site? This feature uses Javascript and cookies to remember the state of each collapsible block, and only affects the user\'s own view.';
|
||||
$string['configallowusermailcharset'] = 'Enabling this, every user in the site will be able to specify his own charset for email.';
|
||||
$string['configallowuserswitchrolestheycantassign'] = 'By default, moodle/role:assign is required for users to switch roles. Enabling this setting removes this requirement, and results in the roles available in the "Switch role to" dropdown menu being determined by settings in the "Allow role assignments" table only.
|
||||
It is recommended that the settings in the "Allow role assignments" table do not allow users to switch to a role with more capabilities than their existing role.';
|
||||
$string['configallowuserthemes'] = 'If you enable this, then users will be allowed to set their own themes. User themes override site themes (but not course themes)';
|
||||
@ -187,6 +185,7 @@ $string['configdefaultuserroleid'] = 'All logged in users will be given the capa
|
||||
$string['configdeleteincompleteusers'] = 'After this period, old not fully setup accounts are deleted.';
|
||||
$string['configdeleteunconfirmed'] = 'If you are using email authentication, this is the period within which a response will be accepted from users. After this period, old unconfirmed accounts are deleted.';
|
||||
$string['configdenyemailaddresses'] = 'To deny email addresses from particular domains list them here in the same way. All other domains will be accepted. To deny subdomains add the domain with a preceding \'.\'. eg <strong>hotmail.com yahoo.co.uk .live.com</strong>';
|
||||
$string['configenabledevicedetection'] = 'Enables detection of mobiles, smartphones, tablets or default devices (desktop PCs, laptops, etc) for the application of themes and other features.';
|
||||
$string['configdigestmailtime'] = 'People who choose to have emails sent to them in digest form will be emailed the digest daily. This setting controls which time of day the daily mail will be sent (the next cron that runs after this hour will send it).';
|
||||
$string['configdisableuserimages'] = 'Disable the ability for users to change user profile images.';
|
||||
$string['configdisplayloginfailures'] = 'This will display information to selected users about previous failed logins.';
|
||||
@ -202,6 +201,7 @@ $string['configenablecourserequests'] = 'This will allow any user to request a c
|
||||
$string['configenableglobalsearch'] = 'This setting enables global text searching in resources and activities, it is not compatible with PHP 4.';
|
||||
$string['configenablegroupmembersonly'] = 'If enabled, access to activities can be restricted to group members only. This may result in an increased server load. In addition, gradebook categories must be set up in a certain way to ensure that activities are hidden from non-group members.';
|
||||
$string['configenablehtmlpurifier'] = 'Use HTML Purifier instead of KSES for cleaning of untrusted text. HTML Purifier is actively developed and is believed to be more secure, but it is more resource intensive. Expect minor visual differences in the resulting html code. Please note that embed and object tags can not be enabled, MathML tags and old lang tags are not supported.';
|
||||
$string['configenablemobilewebservice'] = 'Enable mobile service for the official Moodle app or other app requesting it. For more information, read the {$a}';
|
||||
$string['configenablerssfeeds'] = 'This switch will enable RSS feeds from across the site. To actually see any change you will need to enable RSS feeds in the individual modules too - go to the Modules settings under Admin Configuration.';
|
||||
$string['configenablerssfeedsdisabled'] = 'It is not available because RSS feeds are disabled in all the Site. To enable them, go to the Variables settings under Admin Configuration.';
|
||||
$string['configenablerssfeedsdisabled2'] = 'RSS feeds are disabled at the server level. You need to enable them first in Server/RSS.';
|
||||
@ -239,11 +239,6 @@ $string['configintroadmin'] = 'On this page you should configure your main admin
|
||||
$string['configintrosite'] = 'This page allows you to configure the front page and name of this new site. You can come back here later to change these settings any time using the Administration menus.';
|
||||
$string['configintrotimezones'] = 'This page will search for new information about world timezones (including daylight savings time rules) and update your local database with this information. These locations will be checked, in order: {$a} This procedure is generally very safe and can not break normal installations. Do you wish to update your timezones now?';
|
||||
$string['configiplookup'] = 'When you click on an IP address (such as 34.12.222.93), such as in the logs, you are shown a map with a best guess of where that IP is located. There are different plugins for this that you can choose from, each has benefits and disadvantages.';
|
||||
$string['configjabberhost'] = 'The server to connect to to send jabber message notifications';
|
||||
$string['configjabberserver'] = 'XMPP host ID (can be left empty if the same as Jabber host)';
|
||||
$string['configjabberusername'] = 'The user name to use when connecting to the Jabber server';
|
||||
$string['configjabberpassword'] = 'The password to use when connecting to the Jabber server';
|
||||
$string['configjabberport'] = 'The port to use when connecting to the Jabber server';
|
||||
$string['configkeeptagnamecase'] = 'Check this if you want tag names to keep the original casing as entered by users who created them';
|
||||
$string['configlang'] = 'Choose a default language for the whole site. Users can override this setting using the language menu or the setting in their personal profile.';
|
||||
$string['configlangstringcache'] = 'Caches all the language strings into compiled files in the data directory. If you are translating Moodle or changing strings in the Moodle source code then you may want to switch this off. Otherwise leave it on to see performance benefits.';
|
||||
@ -255,7 +250,6 @@ $string['configlocale'] = 'Choose a sitewide locale - this will override the for
|
||||
$string['configloginhttps'] = 'Turning this on will make Moodle use a secure https connection just for the login page (providing a secure login), and then afterwards revert back to the normal http URL for general speed. CAUTION: this setting REQUIRES https to be specifically enabled on the web server - if it is not then YOU COULD LOCK YOURSELF OUT OF YOUR SITE.';
|
||||
$string['configloglifetime'] = 'This specifies the length of time you want to keep logs about user activity. Logs that are older than this age are automatically deleted. It is best to keep logs as long as possible, in case you need them, but if you have a very busy server and are experiencing performance problems, then you may want to lower the log lifetime. Values lower than 30 are not recommended because statistics may not work properly.';
|
||||
$string['configlookahead'] = 'Days to look ahead';
|
||||
$string['configmailnewline'] = 'Newline characters used in mail messages. CRLF is required according to RFC 822bis, some mail servers do automatic conversion from LF to CRLF, other mail servers do incorrect conversion from CRLF to CRCRLF, yet others reject mails with bare LF (qmail for example). Try changing this setting if you are having problems with undelivered emails or double newlines.';
|
||||
$string['configmaxbytes'] = 'This specifies a maximum size that uploaded files can be throughout the whole site. This setting is limited by the PHP settings post_max_size and upload_max_filesize, as well as the Apache setting LimitRequestBody. In turn, maxbytes limits the range of sizes that can be chosen at course level or module level. If \'Server Limit\' is chosen, the server maximum allowed by the server will be used.';
|
||||
$string['configmaxconsecutiveidentchars'] = 'Passwords must not have more than this number of consecutive identical characters. Use 0 to disable this check.';
|
||||
$string['configmaxeditingtime'] = 'This specifies the amount of time people have to re-edit forum postings, glossary comments etc. Usually 30 minutes is a good value.';
|
||||
@ -276,7 +270,6 @@ $string['configmypagelocked'] = 'This setting prevents the default page from bei
|
||||
$string['confignavcourselimit'] = 'Limits the number of courses shown to the user when they are either not logged in or are not enrolled in any courses.';
|
||||
$string['confignavshowallcourses'] = 'Setting this ensures that all courses on the site are shown in the navigation at all times.';
|
||||
$string['confignavshowcategories'] = 'Show course categories in the navigation bar and navigation blocks. This does not occur with courses the user is currently enrolled in, they will still be listed under mycourses without categories.';
|
||||
$string['confignoreplyaddress'] = 'Emails are sometimes sent out on behalf of a user (eg forum posts). The email address you specify here will be used as the "From" address in those cases when the recipients should not be able to reply directly to the user (eg when a user chooses to keep their address private).';
|
||||
$string['confignotifyloginfailures'] = 'If login failures have been recorded, email notifications can be sent out. Who should see these notifications?';
|
||||
$string['confignotifyloginthreshold'] = 'If notifications about failed logins are active, how many failed login attempts by one user or one IP address is it worth notifying about?';
|
||||
$string['confignotloggedinroleid'] = 'Users who are not logged in to the site will be treated as if they have this role granted to them at the site context. Guest is almost always what you want here, but you might want to create roles that are less or more restrictive. Things like creating posts still require the user to log in properly.';
|
||||
@ -329,14 +322,10 @@ $string['configshowcommentscount'] = 'Show comments count, it will cost one more
|
||||
$string['configshowsiteparticipantslist'] = 'All of these site students and site teachers will be listed on the site participants list. Who shall be allowed to see this site participants list?';
|
||||
$string['configsitedefaultlicense'] = 'Default site licence';
|
||||
$string['configsitedefaultlicensehelp'] = 'The default licence for publishing content on this site';
|
||||
$string['configsitemailcharset'] = 'All the emails generated by your site will be sent in the charset specified here. Anyway, every individual user will be able to adjust it if the next setting is enabled.';
|
||||
$string['configsitemaxcategorydepth'] = 'Maximum category depth';
|
||||
$string['configsitemaxcategorydepthhelp'] = 'This specifies the maximum depth of child categories shown';
|
||||
$string['configslasharguments'] = 'Files (images, uploads etc) are provided via a script using \'slash arguments\'. This method allows files to be more easily cached in web browsers, proxy servers etc. Unfortunately, some PHP servers don\'t allow this method, so if you have trouble viewing uploaded files or images (eg user pictures), disable this setting.';
|
||||
$string['configsmartpix'] = 'With this on, icons are served through a PHP script that searches the current theme, then all parent themes, then the Moodle /pix folder. This reduces the need to duplicate image files within themes, but has a slight performance cost.';
|
||||
$string['configsmtphosts'] = 'Give the full name of one or more local SMTP servers that Moodle should use to send mail (eg \'mail.a.com\' or \'mail.a.com;mail.b.com\'). To specify a non-default port (i.e other than port 25), you can use the [server]:[port] syntax (eg \'mail.a.com:587\'. If you leave it blank, Moodle will use the PHP default method of sending mail.';
|
||||
$string['configsmtpmaxbulk'] = 'Maximum number of messages sent per SMTP session. Grouping messages may speed up the sending of emails. Values lower than 2 force creation of new SMTP session for each email.';
|
||||
$string['configsmtpuser'] = 'If you have specified an SMTP server above, and the server requires authentication, then enter the username and password here.';
|
||||
$string['configstartwday'] = 'Start of week';
|
||||
$string['configstatsfirstrun'] = 'This specifies how far back the logs should be processed <b>the first time</b> the cronjob wants to process statistics. If you have a lot of traffic and are on shared hosting, it\'s probably not a good idea to go too far back, as it could take a long time to run and be quite resource intensive. (Note that for this setting, 1 month = 28 days. In the graphs and reports generated, 1 month = 1 calendar month.)';
|
||||
$string['configstatsmaxruntime'] = 'Stats processing can be quite intensive, so use a combination of this field and the next one to specify when it will run and how long for.';
|
||||
@ -450,6 +439,12 @@ $string['deletingqtype'] = 'Deleting question type \'{$a}\'';
|
||||
$string['density'] = 'Density';
|
||||
$string['denyemailaddresses'] = 'Denied email domains';
|
||||
$string['development'] = 'Development';
|
||||
$string['devicedetectregex'] = 'Device detection regular expressions';
|
||||
$string['devicedetectregex_desc'] = '<p>By default, Moodle can detect devices of the type default (desktop PCs, laptops, etc), mobile (phones and small hand held devices), tablet (iPads, Android tablets) and legacy (Internet Explorer 6 users). The theme selector can be used to apply separate themes to all of these. This setting allows regular expressions that allow the detection of extra device types (these take precedence over the default types).</p>
|
||||
<p>For example, you could enter the regular expression \'/(MIDP-1.0|Maemo|Windows CE)/\' to detect some commonly used feasture phones add the return value \'featurephone\'. This adds \'featurephone\' on the theme selector that would allow you to add a theme that would be used on these devices. Other phones would still use the theme selected for the mobile device type.</p>';
|
||||
$string['devicedetectregexexpression'] = 'Regular expression';
|
||||
$string['devicedetectregexvalue'] = 'Return value';
|
||||
$string['devicetype'] = 'Device type';
|
||||
$string['digestmailtime'] = 'Hour to send digest emails';
|
||||
$string['disableuserimages'] = 'Disable user profile images';
|
||||
$string['displayerrorswarning'] = 'Enabling the PHP setting <em>display_errors</em> is not recommended on production sites because some error messages may reveal sensitive information about your server.';
|
||||
@ -491,9 +486,11 @@ $string['enablecomments'] = 'Enable comments';
|
||||
$string['enablecourseajax'] = 'Enable AJAX course editing';
|
||||
$string['enablecourseajax_desc'] = 'Allow AJAX when editing main course pages. Note that the course format and the theme must support AJAX editing and the user has to enable AJAX in their profiles, too.';
|
||||
$string['enablecourserequests'] = 'Enable course requests';
|
||||
$string['enabledevicedetection'] = 'Enable device detection';
|
||||
$string['enableglobalsearch'] = 'Enable global search';
|
||||
$string['enablegroupmembersonly'] = 'Enable group members only';
|
||||
$string['enablehtmlpurifier'] = 'Enable HTML Purifier';
|
||||
$string['enablemobilewebservice'] = 'Enable mobile web service';
|
||||
$string['enablerecordcache'] = 'Enable record cache';
|
||||
$string['enablerssfeeds'] = 'Enable RSS feeds';
|
||||
$string['enablesafebrowserintegration'] = 'Enable Safe Exam Browser integration';
|
||||
@ -623,12 +620,6 @@ It is recommended to install local copy of free GeoLite City database from MaxMi
|
||||
IP address location is displayed on simple map or using Google Maps. Please note that you need to have a Google account and apply for free Google Maps API key to enable interactive maps.';
|
||||
$string['iplookupmaxmindnote'] = 'This product includes GeoLite data created by MaxMind, available from <a href="http://www.maxmind.com/">http://www.maxmind.com/</a>.';
|
||||
$string['iplookupnetgeonote'] = 'The NetGeo server is currently being used to look up geographical information. For more accurate results we recommend installing a local copy of the MaxMind GeoLite database.';
|
||||
$string['jabber'] = 'Jabber';
|
||||
$string['jabberhost'] = 'Jabber host';
|
||||
$string['jabberserver'] = 'Jabber server';
|
||||
$string['jabberusername'] = 'Jabber user name';
|
||||
$string['jabberpassword'] = 'Jabber password';
|
||||
$string['jabberport'] = 'Jabber port';
|
||||
$string['keeptagnamecase'] = 'Keep tag name casing';
|
||||
$string['lang'] = 'Default language';
|
||||
$string['langcache'] = 'Cache language menu';
|
||||
@ -674,8 +665,6 @@ $string['logguests_help'] = 'This setting enables logging of actions by guest ac
|
||||
$string['loginhttps'] = 'Use HTTPS for logins';
|
||||
$string['loglifetime'] = 'Keep logs for';
|
||||
$string['longtimewarning'] = '<b>Please note that this process can take a long time.</b>';
|
||||
$string['mail'] = 'Email';
|
||||
$string['mailnewline'] = 'Newline characters in mail';
|
||||
$string['maintenancemode'] = 'In maintenance mode';
|
||||
$string['maintfileopenerror'] = 'Error opening maintenance files!';
|
||||
$string['maintinprogress'] = 'Maintenance is in progress...';
|
||||
@ -752,11 +741,11 @@ $string['neverdeleteruns'] = 'Never delete runs';
|
||||
$string['nobookmarksforuser'] = 'You do not have any bookmarks.';
|
||||
$string['nodatabase'] = 'No database';
|
||||
$string['nochanges'] = 'No changes';
|
||||
$string['nohttpsformobilewarning'] = 'It is recommended to enable HTTPS with a valid certificate. The Moodle app will always try to use a secured connection first.';
|
||||
$string['nolangupdateneeded'] = 'All your language packs are up to date, no update is needed';
|
||||
$string['nomissingstrings'] = 'No missing strings';
|
||||
$string['nonewsettings'] = 'No new settings were added during this upgrade.';
|
||||
$string['nonexistentbookmark'] = 'The bookmark you requested does not exist.';
|
||||
$string['noreplyaddress'] = 'No-reply address';
|
||||
$string['noresults'] = 'No results found.';
|
||||
$string['noroles'] = 'No roles';
|
||||
$string['notifications'] = 'Notifications';
|
||||
@ -948,7 +937,6 @@ $string['showdetails'] = 'Show details';
|
||||
$string['simpletest'] = 'Unit tests';
|
||||
$string['simplexmlrequired'] = 'The SimpleXML PHP extension is now required by Moodle.';
|
||||
$string['sitelangchanged'] = 'Site language setting changed successfully';
|
||||
$string['sitemailcharset'] = 'Character set';
|
||||
$string['sitemaintenance'] = 'The site is undergoing maintenance and is currently not available';
|
||||
$string['sitemaintenancemode'] = 'Maintenance mode';
|
||||
$string['sitemaintenanceoff'] = 'Maintenance mode has been disabled and the site is running normally again';
|
||||
@ -963,10 +951,6 @@ $string['sitepolicyguest_help'] = 'If you have a site policy that all guests mus
|
||||
$string['sitesectionhelp'] = 'If selected, a topic section will be displayed on the site\'s front page.';
|
||||
$string['slasharguments'] = 'Use slash arguments';
|
||||
$string['smartpix'] = 'Smart pix search';
|
||||
$string['smtphosts'] = 'SMTP hosts';
|
||||
$string['smtpmaxbulk'] = 'SMTP session limit';
|
||||
$string['smtppass'] = 'SMTP password';
|
||||
$string['smtpuser'] = 'SMTP username';
|
||||
$string['soaprecommended'] = 'Installing the optional soap extension is useful for web services and some contrib modules.';
|
||||
$string['spellengine'] = 'Spell engine';
|
||||
$string['splrequired'] = 'The SPL PHP extension is now required by Moodle.';
|
||||
@ -982,6 +966,7 @@ $string['stickyblocksduplicatenotice'] = 'If any block you add here is already p
|
||||
$string['stickyblocksmymoodle'] = 'My Moodle';
|
||||
$string['stickyblockspagetype'] = 'Page type to configure';
|
||||
$string['stripalltitletags'] = 'Remove HTML tags from all activity names';
|
||||
$string['supportcontact'] = 'Support contact';
|
||||
$string['supportemail'] = 'Support email';
|
||||
$string['supportname'] = 'Support name';
|
||||
$string['supportpage'] = 'Support page';
|
||||
@ -993,7 +978,9 @@ $string['tabselectedtofront'] = 'On tables with tabs, should the row with the cu
|
||||
$string['tabselectedtofronttext'] = 'Bring selected tab row to front';
|
||||
$string['themedesignermode'] = 'Theme designer mode';
|
||||
$string['themelist'] = 'Theme list';
|
||||
$string['themenoselected'] = 'No theme selected';
|
||||
$string['themeresetcaches'] = 'Clear theme caches';
|
||||
$string['themeselect'] = 'Select theme';
|
||||
$string['themeselector'] = 'Theme selector';
|
||||
$string['themesettings'] = 'Theme settings';
|
||||
$string['therewereerrors'] = 'There were errors in your data';
|
||||
|
@ -277,6 +277,7 @@ $string['invalidcoursemodule'] = 'Invalid course module ID';
|
||||
$string['invalidcoursenameshort'] = 'Invalid short course name';
|
||||
$string['invaliddata'] = 'Data submitted is invalid';
|
||||
$string['invaliddatarootpermissions'] = 'Invalid permissions detected in $CFG->dataroot directory, administrator has to fix permissions.';
|
||||
$string['invaliddevicetype'] = 'Invalid device type';
|
||||
$string['invalidelementid'] = 'Incorrect element id!';
|
||||
$string['invalidentry'] = 'This is not valid entry!';
|
||||
$string['invalidevent'] = 'Invalid event';
|
||||
|
@ -37,19 +37,23 @@ $string['blockcontact'] = 'Block contact';
|
||||
$string['blockedmessages'] = '{$a} message(s) to/from blocked users';
|
||||
$string['blockedusers'] = 'Blocked users ({$a})';
|
||||
$string['blocknoncontacts'] = 'Prevent non-contacts from messaging me';
|
||||
$string['cannotsavemessageprefs'] = 'Could not save user messaging preferences';
|
||||
$string['contactlistempty'] = 'Your contact list is empty';
|
||||
$string['contacts'] = 'Contacts';
|
||||
$string['context'] = 'context';
|
||||
$string['couldnotfindpreference'] = 'Could not load preference {$a}. Does the component and name you supplied to message_send() match a row in message_providers? Message providers must appear in the database so users can configure how they will be notified when they receive messages.';
|
||||
$string['defaultmessageoutputs'] = 'Default message outputs';
|
||||
$string['defaults'] = 'Defaults';
|
||||
$string['deletemessagesdays'] = 'Number of days before old messages are automatically deleted';
|
||||
$string['disabled'] = 'Messaging is disabled on this site';
|
||||
$string['disallowed'] = 'Disallowed';
|
||||
$string['discussion'] = 'Discussion';
|
||||
$string['editmymessage'] = 'Messaging';
|
||||
$string['emailmessages'] = 'Email messages when I am offline';
|
||||
$string['emailtagline'] = 'This is a copy of a message sent to you at "{$a->sitename}". Go to {$a->url} to reply.';
|
||||
$string['emptysearchstring'] = 'You must search for something';
|
||||
$string['errorcallingprocessor'] = 'Error calling defined processor';
|
||||
$string['errortranslatingdefault'] = 'Error translating default setting provided by plugin, using system defaults instead.';
|
||||
$string['forced'] = 'Forced';
|
||||
$string['formorethan'] = 'For more than';
|
||||
$string['guestnoeditmessage'] = 'Guest user can not edit messaging options';
|
||||
$string['guestnoeditmessageother'] = 'Guest user can not edit other user messaging options';
|
||||
@ -64,6 +68,8 @@ $string['loggedindescription'] = 'When I\'m logged in';
|
||||
$string['loggedoff'] = 'Not online';
|
||||
$string['loggedoffdescription'] = 'When I\'m offline';
|
||||
$string['managecontacts'] = 'Manage my contacts';
|
||||
$string['managemessageoutputs'] = 'Manage message outputs';
|
||||
$string['messageoutputs'] = 'Message outputs';
|
||||
$string['mostrecent'] = 'Recent messages';
|
||||
$string['mostrecentconversations'] = 'Recent conversations';
|
||||
$string['mostrecentnotifications'] = 'Recent notifications';
|
||||
@ -83,6 +89,7 @@ $string['nomessages'] = 'No messages waiting';
|
||||
$string['nomessagesfound'] = 'No messages were found';
|
||||
$string['noreply'] = 'Do not reply to this message';
|
||||
$string['nosearchresults'] = 'There were no results from your search';
|
||||
$string['notpermitted'] = 'Not permitted';
|
||||
$string['offline'] = 'Offline';
|
||||
$string['offlinecontacts'] = 'Offline contacts ({$a})';
|
||||
$string['online'] = 'Online';
|
||||
@ -90,7 +97,13 @@ $string['onlinecontacts'] = 'Online contacts ({$a})';
|
||||
$string['onlyfromme'] = 'Only messages from me';
|
||||
$string['onlymycourses'] = 'Only in my courses';
|
||||
$string['onlytome'] = 'Only messages to me';
|
||||
$string['outputdisabled'] = 'Output disabled';
|
||||
$string['outputdoesnotexist'] = 'Message output does not exists';
|
||||
$string['outputenabled'] = 'Output enabled';
|
||||
$string['outputnotavailable'] = 'Not available';
|
||||
$string['outputnotconfigured'] = 'Not configured';
|
||||
$string['pagerefreshes'] = 'This page refreshes automatically every {$a} seconds';
|
||||
$string['permitted'] = 'Permitted';
|
||||
$string['private_config'] = 'Popup message window';
|
||||
$string['processortag'] = 'Destination';
|
||||
$string['providers_config'] = 'Configure notification methods for incoming messages';
|
||||
@ -103,6 +116,8 @@ $string['search'] = 'Search';
|
||||
$string['searchforperson'] = 'Search for a person';
|
||||
$string['searchmessages'] = 'Search messages';
|
||||
$string['searchcombined'] = 'Search people and messages';
|
||||
$string['sendingvia'] = 'Sending "{$a->provider}" via "{$a->processor}"';
|
||||
$string['sendingviawhen'] = 'Sending "{$a->provider}" via "{$a->processor}" when {$a->state}';
|
||||
$string['sendmessage'] = 'Send message';
|
||||
$string['sendmessageto'] = 'Send message to {$a}';
|
||||
$string['sendmessagetopopup'] = 'Send message to {$a} - new window';
|
||||
@ -112,6 +127,7 @@ $string['showmessagewindow'] = 'Popup window on new message';
|
||||
$string['strftimedaydatetime'] = '%A, %d %B %Y, %I:%M %p';
|
||||
$string['timenosee'] = 'Minutes since I was last seen online';
|
||||
$string['timesent'] = 'Time sent';
|
||||
$string['touserdoesntexist'] = 'You can not send a message to a user id ({$a}) that doesn\'t exist';
|
||||
$string['unblockcontact'] = 'Unblock contact';
|
||||
$string['unreadmessages'] = 'Unread messages ({$a})';
|
||||
$string['unreadnewmessages'] = 'New messages ({$a})';
|
||||
|
@ -906,7 +906,6 @@ $string['latestlanguagepack'] = 'Check for latest language pack on moodle.org';
|
||||
$string['layouttable'] = 'Layout table';
|
||||
$string['leavetokeep'] = 'Leave blank to keep current password';
|
||||
$string['legacythemeinuse'] = 'This site is being displayed to you in compatibility mode because your browser is too old.';
|
||||
$string['legacythemesaved'] = 'New legacy theme saved';
|
||||
$string['license'] = 'Licence';
|
||||
$string['licenses'] = 'Licences';
|
||||
$string['liketologin'] = 'Would you like to log in now with a full user account?';
|
||||
@ -1603,6 +1602,8 @@ $string['summary'] = 'Summary';
|
||||
$string['summary_help'] = 'The idea of a summary is a short text to prepare students for the activities within the topic or week. The text is shown on the course page under the section name.';
|
||||
$string['summaryof'] = 'Summary of {$a}';
|
||||
$string['supplyinfo'] = 'More details';
|
||||
$string['switchdevicedefault'] = 'Switch to the standard theme';
|
||||
$string['switchdevicerecommended'] = 'Switch to the recommended theme for your device';
|
||||
$string['switchrolereturn'] = 'Return to my normal role';
|
||||
$string['switchroleto'] = 'Switch role to...';
|
||||
$string['tag'] = 'Tag';
|
||||
@ -1692,8 +1693,6 @@ $string['uploadthisfile'] = 'Upload this file';
|
||||
$string['url'] = 'URL';
|
||||
$string['used'] = 'Used';
|
||||
$string['usedinnplaces'] = 'Used in {$a} places';
|
||||
$string['useformaintheme'] = 'Use for modern browsers';
|
||||
$string['useforlegacytheme'] = 'Use for old browsers';
|
||||
$string['usemessageform'] = 'or use the form below to send a message to the selected students';
|
||||
$string['user'] = 'User';
|
||||
$string['userconfirmed'] = 'Confirmed {$a}';
|
||||
@ -1723,6 +1722,7 @@ $string['userswithfiles'] = 'Users with files';
|
||||
$string['useruploadtype'] = 'User upload type: {$a}';
|
||||
$string['userviewingsettings'] = 'Profile settings for {$a}';
|
||||
$string['userzones'] = 'User zones';
|
||||
$string['usetheme'] = 'Use theme';
|
||||
$string['usingexistingcourse'] = 'Using existing course';
|
||||
$string['valuealreadyused'] = 'This value has already been used.';
|
||||
$string['version'] = 'Version';
|
||||
|
@ -37,7 +37,9 @@ $string['deletenotes'] = 'Delete all notes';
|
||||
$string['editnote'] = 'Edit note';
|
||||
$string['enablenotes'] = 'Enable notes';
|
||||
$string['groupaddnewnote'] = 'Add a common note';
|
||||
$string['invalidcourseid'] = 'Invalid course id: {$a}';
|
||||
$string['invalidid'] = 'Invalid note ID specified';
|
||||
$string['invaliduserid'] = 'Invalid user id: {$a}';
|
||||
$string['nocontent'] = 'Note content can not be empty';
|
||||
$string['nonotes'] = 'There are no notes of this type yet';
|
||||
$string['nopermissiontodelete'] = 'You may not delete this note';
|
||||
|
@ -23,6 +23,7 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['addcategory'] = 'Add category';
|
||||
$string['adminreport'] = 'Report on possible problems in your question database.';
|
||||
$string['availableq'] = 'Available?';
|
||||
$string['badbase'] = 'Bad base before **: {$a}**';
|
||||
@ -52,7 +53,9 @@ $string['cannotwriteto'] = 'Cannot write exported questions to {$a}';
|
||||
$string['categorycurrent'] = 'Current category';
|
||||
$string['categorycurrentuse'] = 'Use this category';
|
||||
$string['categorydoesnotexist'] = 'This category does not exist';
|
||||
$string['categoryinfo'] = 'Category info';
|
||||
$string['categorymoveto'] = 'Save in category';
|
||||
$string['categorynamecantbeblank'] = 'The category name cannot be blank.';
|
||||
$string['clicktoflag'] = 'Click to flag this question';
|
||||
$string['clicktounflag'] = 'Click to un-flag this question';
|
||||
$string['contexterror'] = 'You shouldn\'t have got here if you\'re not moving a category to another context.';
|
||||
@ -76,6 +79,8 @@ $string['cwrqpfsnoprob'] = 'No question categories in your site are affected by
|
||||
$string['defaultfor'] = 'Default for {$a}';
|
||||
$string['defaultinfofor'] = 'The default category for questions shared in context \'{$a}\'.';
|
||||
$string['deletecoursecategorywithquestions'] = 'There are questions in the question bank associated with this course category. If you proceed, they will be deleted. You may wish to move them first, using the question bank interface.';
|
||||
$string['deletequestioncheck'] = 'Are you absolutely sure you want to delete \'{$a}\'?';
|
||||
$string['deletequestionscheck'] = 'Are you absolutely sure you want to delete the following questions?<br /><br />{$a}';
|
||||
$string['disabled'] = 'Disabled';
|
||||
$string['disterror'] = 'The distribution {$a} caused problems';
|
||||
$string['donothing'] = 'Don\'t copy or move files or change links.';
|
||||
@ -91,6 +96,7 @@ Each category has a context which determines where the questions in the category
|
||||
|
||||
Categories are also used for random questions, as questions are selected from a particular category.';
|
||||
$string['editcategories_link'] = 'question/category';
|
||||
$string['editcategory'] = 'Edit category';
|
||||
$string['editingcategory'] = 'Editing a category';
|
||||
$string['editingquestion'] = 'Editing a question';
|
||||
$string['editthiscategory'] = 'Edit this category';
|
||||
@ -125,6 +131,7 @@ $string['exportquestions_help'] = 'This function enables the export of a complet
|
||||
$string['exportquestions_link'] = 'question/export';
|
||||
$string['filecantmovefrom'] = 'The questions files cannot be moved because you do not have permission to remove files from the place you are trying to move questions from.';
|
||||
$string['filecantmoveto'] = 'The question files cannot be moved or copied becuase you do not have permission to add files to the place you are trying to move the questions to.';
|
||||
$string['fileformat'] = 'File format';
|
||||
$string['filesareacourse'] = 'the course files area';
|
||||
$string['filesareasite'] = 'the site files area';
|
||||
$string['filestomove'] = 'Move / copy files to {$a}?';
|
||||
@ -136,26 +143,36 @@ $string['getcategoryfromfile'] = 'Get category from file';
|
||||
$string['getcontextfromfile'] = 'Get context from file';
|
||||
$string['changepublishstatuscat'] = '<a href="{$a->caturl}">Category "{$a->name}"</a> in course "{$a->coursename}" will have it\'s sharing status changed from <strong>{$a->changefrom} to {$a->changeto}</strong>.';
|
||||
$string['chooseqtypetoadd'] = 'Choose a question type to add';
|
||||
$string['editquestions'] = 'Edit questions';
|
||||
$string['ignorebroken'] = 'Ignore broken links';
|
||||
$string['impossiblechar'] = 'Impossible character {$a} detected as parenthesis character';
|
||||
$string['importcategory'] = 'Import category';
|
||||
$string['importcategory_help'] = 'This setting determines the category into which the imported questions will go.
|
||||
|
||||
Certain import formats, such as GIFT and Moodle XML, may include category and context data in the import file. To make use of this data, rather than the selected category, the appropriate checkboxes should be ticked. If categories specified in the import file do not exist, they will be created.';
|
||||
$string['importerror'] = 'An error occurred during import processing';
|
||||
$string['importerrorquestion'] = 'Error importing question';
|
||||
$string['importingquestions'] = 'Importing {$a} questions from file';
|
||||
$string['importparseerror'] = 'Error(s) found parsing the import file. No questions have been imported. To import any good questions try again setting \'Stop on error\' to \'No\'';
|
||||
$string['importquestions'] = 'Import questions from file';
|
||||
$string['importquestions_help'] = 'This function enables questions in a variety of formats to be imported via text file. Note that the file must use UTF-8 encoding.';
|
||||
$string['importquestions_link'] = 'question/import';
|
||||
$string['importwrongfiletype'] = 'The type of the file you selected ({$a->actualtype}) does not match the type expected by this import format ({$a->expectedtype}).';
|
||||
$string['invalidarg'] = 'No valid arguments supplied or incorrect server configuration';
|
||||
$string['invalidcategoryidforparent'] = 'Invalid category id for parent!';
|
||||
$string['invalidcategoryidtomove'] = 'Invalid category id to move!';
|
||||
$string['invalidconfirm'] = 'Confirmation string was incorrect';
|
||||
$string['invalidcontextinhasanyquestions'] = 'Invalid context passed to question_context_has_any_questions.';
|
||||
$string['invalidpenalty'] = 'Invalid penalty';
|
||||
$string['invalidwizardpage'] = 'Incorrect or no wizard page specified!';
|
||||
$string['lastmodifiedby'] = 'Last modified by';
|
||||
$string['linkedfiledoesntexist'] = 'Linked file {$a} doesn\'t exist';
|
||||
$string['makechildof'] = 'Make child of \'{$a}\'';
|
||||
$string['maketoplevelitem'] = 'Move to top level';
|
||||
$string['matcherror'] = 'Grades do not match grade options - question skipped';
|
||||
$string['matchgrades'] = 'Match grades';
|
||||
$string['matchgradeserror'] = 'Error if grade not listed';
|
||||
$string['matchgradesnearest'] = 'Nearest grade if not listed';
|
||||
$string['matchgrades_help'] = 'Imported grades must match one of the fixed list of valid grades - 100, 90, 80, 75, 70, 66.666, 60, 50, 40, 33.333, 30, 25, 20, 16.666, 14.2857, 12.5, 11.111, 10, 5, 0 (also negative values). If not, there are two options:
|
||||
|
||||
* Error if grade not listed - If a question contains any grades not found in the list an error is displayed and that question will not be imported
|
||||
@ -171,6 +188,7 @@ $string['movedquestionsandcategories'] = 'Moved questions and question categorie
|
||||
$string['movelinksonly'] = 'Just change where links point to, do not move or copy files.';
|
||||
$string['moveq'] = 'Move question(s)';
|
||||
$string['moveqtoanothercontext'] = 'Move question to another context.';
|
||||
$string['moveto'] = 'Move to >>';
|
||||
$string['movingcategory'] = 'Moving category';
|
||||
$string['movingcategoryandfiles'] = 'Are you sure you want to move category {$a->name} and all child categories to context for "{$a->contextto}"?<br /> We have detected {$a->urlcount} files linked from questions in {$a->fromareaname}, would you like to copy or move these to {$a->toareaname}?';
|
||||
$string['movingcategorynofiles'] = 'Are you sure you want to move category "{$a->name}" and all child categories to context for "{$a->contextto}"?';
|
||||
@ -182,6 +200,7 @@ $string['nocate'] = 'No such category {$a}!';
|
||||
$string['nopermissionadd'] = 'You don\'t have permission to add questions here.';
|
||||
$string['nopermissionmove'] = 'You don\'t have permission to move questions from here. You must save the question in this category or save it as a new question.';
|
||||
$string['noprobs'] = 'No problems found in your question database.';
|
||||
$string['notenoughanswers'] = 'This type of question requires at least {$a} answers';
|
||||
$string['notenoughdatatoeditaquestion'] = 'Neither a question id, nor a category id and question type, was specified.';
|
||||
$string['notenoughdatatomovequestions'] = 'You need to provide the question ids of questions you want to move.';
|
||||
$string['notflagged'] = 'Not flagged';
|
||||
@ -191,6 +210,7 @@ $string['parentcategory_help'] = 'The parent category is the one in which the ne
|
||||
$string['parentcategory_link'] = 'question/category';
|
||||
$string['parenthesisinproperclose'] = 'Parenthesis before ** is not properly closed in {$a}**';
|
||||
$string['parenthesisinproperstart'] = 'Parenthesis before ** is not properly started in {$a}**';
|
||||
$string['parsingquestions'] = 'Parsing questions from import file.';
|
||||
$string['penaltyfactor'] = 'Penalty factor';
|
||||
$string['penaltyfactor_help'] = 'This setting determines what fraction of the achieved score is subtracted for each wrong response. It is only applicable if the quiz is run in adaptive mode.
|
||||
|
||||
@ -207,12 +227,16 @@ $string['questioncategory'] = 'Question category';
|
||||
$string['questioncatsfor'] = 'Question categories for \'{$a}\'';
|
||||
$string['questiondoesnotexist'] = 'This question does not exist';
|
||||
$string['questionname'] = 'Question name';
|
||||
$string['questionno'] = 'Question {$a}';
|
||||
$string['questionsaveerror'] = 'Errors occur during saving question - ({$a})';
|
||||
$string['questionsinuse'] = '(* Questions marked by an asterisk are already in use in some quizzes. These question will not be deleted from these quizzes but only from the category list.)';
|
||||
$string['questionsmovedto'] = 'Questions still in use moved to "{$a}" in the parent course category.';
|
||||
$string['questionsrescuedfrom'] = 'Questions saved from context {$a}.';
|
||||
$string['questionsrescuedfrominfo'] = 'These questions (some of which may be hidden) were saved when context {$a} was deleted because they are still used by some quizzes or other activities.';
|
||||
$string['questiontype'] = 'Question type';
|
||||
$string['questionuse'] = 'Use question in this activity';
|
||||
$string['questionvariant'] = 'Question variant';
|
||||
$string['reviewresponse'] = 'Review response';
|
||||
$string['saveflags'] = 'Save the state of the flags';
|
||||
$string['selectacategory'] = 'Select a category:';
|
||||
$string['selectaqtypefordescription'] = 'Select a question type to see its description.';
|
||||
@ -232,3 +256,116 @@ $string['upgradeproblemunknowncategory'] = 'Problem detected when upgrading ques
|
||||
$string['wrongprefix'] = 'Wrongly formatted nameprefix {$a}';
|
||||
$string['youmustselectaqtype'] = 'You must select a question type.';
|
||||
$string['yourfileshoulddownload'] = 'Your export file should start to download shortly. If not, please <a href="{$a}">click here</a>.';
|
||||
|
||||
$string['action'] = 'Action';
|
||||
$string['addanotherhint'] = 'Add another hint';
|
||||
$string['answer'] = 'Answer';
|
||||
$string['answersaved'] = 'Answer saved';
|
||||
$string['attemptfinished'] = 'Attempt finished';
|
||||
$string['attemptfinishedsubmitting'] = 'Attempt finished submitting: ';
|
||||
$string['behaviourbeingused'] = 'behaviour being used: {$a}';
|
||||
$string['cannotloadquestion'] = 'Could not load question';
|
||||
$string['cannotpreview'] = 'You can\'t preview these questions!';
|
||||
$string['category'] = 'Category';
|
||||
$string['changeoptions'] = 'Change options';
|
||||
$string['check'] = 'Check';
|
||||
$string['clearwrongparts'] = 'Clear incorrect responses';
|
||||
$string['clicktoflag'] = 'Click to flag this question';
|
||||
$string['clicktounflag'] = 'Click to un-flag this question';
|
||||
$string['closepreview'] = 'Close preview';
|
||||
$string['combinedfeedback'] = 'Combined feedback';
|
||||
$string['commented'] = 'Commented: {$a}';
|
||||
$string['comment'] = 'Comment';
|
||||
$string['commentormark'] = 'Make comment or override mark';
|
||||
$string['comments'] = 'Comments';
|
||||
$string['commentx'] = 'Comment: {$a}';
|
||||
$string['complete'] = 'Complete';
|
||||
$string['contexterror'] = 'You shouldn\'t have got here if you\'re not moving a category to another context.';
|
||||
$string['correct'] = 'Correct';
|
||||
$string['correctfeedback'] = 'For any correct response';
|
||||
$string['decimalplacesingrades'] = 'Decimal places in grades';
|
||||
$string['defaultmark'] = 'Default mark';
|
||||
$string['errorsavingflags'] = 'Error saving the flag state.';
|
||||
$string['feedback'] = 'Feedback';
|
||||
$string['fillincorrect'] = 'Fill in correct responses';
|
||||
$string['flagged'] = 'Flagged';
|
||||
$string['flagthisquestion'] = 'Flag this question';
|
||||
$string['generalfeedback'] = 'General feedback';
|
||||
$string['generalfeedback_help'] = 'General feedback is shown to the student after they have attempted the question. Unlike feedback, which depends on the question type and what response the student gave, the same general feedback text is shown to all students.
|
||||
|
||||
You can use the general feedback to give students some background to what knowledge the question was testing, or give them a link to more information they can use if they did not understand the questions.';
|
||||
$string['hidden'] = 'Hidden';
|
||||
$string['hintn'] = 'Hint {no}';
|
||||
$string['hinttext'] = 'Hint text';
|
||||
$string['howquestionsbehave'] = 'How questions behave';
|
||||
$string['howquestionsbehave_help'] = 'Students can interact with the questions in the quiz in various different ways. For example, you may wish the students to enter an answer to each question and then submit the entire quiz, before anything is graded or they get any feedback. That would be \'Deferred feedback\' mode. Alternatively, you may wish for students to submit each question as they go along to get immediate feedback, and if they do not get it right immediately, have another try for fewer marks. That would be \'Interactive with multiple tries\' mode.';
|
||||
$string['importfromcoursefiles'] = '... or choose a course file to import.';
|
||||
$string['importfromupload'] = 'Select a file to upload ...';
|
||||
$string['includesubcategories'] = 'Also show questions from sub-categories';
|
||||
$string['incorrect'] = 'Incorrect';
|
||||
$string['incorrectfeedback'] = 'For any incorrect response';
|
||||
$string['information'] = 'Information';
|
||||
$string['invalidanswer'] = 'Incomplete answer';
|
||||
$string['makecopy'] = 'Make copy';
|
||||
$string['manualgradeoutofrange'] = 'This grade is outside the valid range.';
|
||||
$string['manuallygraded'] = 'Manually graded {$a->mark} with comment: {$a->comment}';
|
||||
$string['mark'] = 'Mark';
|
||||
$string['markedoutof'] = 'Marked out of';
|
||||
$string['markedoutofmax'] = 'Marked out of {$a}';
|
||||
$string['markoutofmax'] = 'Mark {$a->mark} out of {$a->max}';
|
||||
$string['marks'] = 'Marks';
|
||||
$string['noresponse'] = '[No response]';
|
||||
$string['notanswered'] = 'Not answered';
|
||||
$string['notflagged'] = 'Not flagged';
|
||||
$string['notgraded'] = 'Not graded';
|
||||
$string['notshown'] = 'Not shown';
|
||||
$string['notyetanswered'] = 'Not yet answered';
|
||||
$string['notyourpreview'] = 'This preview does not belong to you';
|
||||
$string['options'] = 'Options';
|
||||
$string['parent'] = 'Parent';
|
||||
$string['partiallycorrect'] = 'Partially correct';
|
||||
$string['partiallycorrectfeedback'] = 'For any partially correct response';
|
||||
$string['penaltyforeachincorrecttry'] = 'Penalty for each incorrect try';
|
||||
$string['penaltyforeachincorrecttry_help'] = 'When you run your questions using the \'Interactive with multiple tries\' or \'Adaptive mode\' behaviour, so that the the student will have several tries to get the question right, then this option controls how much they are penalised for each incorrect try.
|
||||
|
||||
The penalty is a proportion of the total question grade, so if the question is worth three marks, and the penalty is 0.3333333, then the student will score 3 if they get the question right first time, 2 if they get it right second try, and 1 of they get it right on the third try.';
|
||||
$string['previewquestion'] = 'Preview question: {$a}';
|
||||
$string['questionbehaviouradminsetting'] = 'Question behaviour settings';
|
||||
$string['questionbehavioursdisabled'] = 'Question behaviours to disable';
|
||||
$string['questionbehavioursdisabledexplained'] = 'Enter a comma separated list of behaviours you do not want to appear in dropdown menu';
|
||||
$string['questionbehavioursorder'] = 'Question behaviours order';
|
||||
$string['questionbehavioursorderexplained'] = 'Enter a comma separated list of behaviours in the order you want them to appear in dropdown menu';
|
||||
$string['questionidmismatch'] = 'Question ids mismatch';
|
||||
$string['questionname'] = 'Question name';
|
||||
$string['questions'] = 'Questions';
|
||||
$string['questionx'] = 'Question {$a}';
|
||||
$string['questiontext'] = 'Question text';
|
||||
$string['requiresgrading'] = 'Requires grading';
|
||||
$string['responsehistory'] = 'Response history';
|
||||
$string['restart'] = 'Start again';
|
||||
$string['restartwiththeseoptions'] = 'Start again with these options';
|
||||
$string['rightanswer'] = 'Right answer';
|
||||
$string['saved'] = 'Saved: {$a}';
|
||||
$string['saveflags'] = 'Save the state of the flags';
|
||||
$string['settingsformultipletries'] = 'Settings for multiple tries';
|
||||
$string['showhidden'] = 'Also show old questions';
|
||||
$string['showmarkandmax'] = 'Show mark and max';
|
||||
$string['showmaxmarkonly'] = 'Show max mark only';
|
||||
$string['showquestiontext'] = 'Show question text in the question list';
|
||||
$string['shown'] = 'Shown';
|
||||
$string['shownumpartscorrect'] = 'Show the number of correct responses';
|
||||
$string['specificfeedback'] = 'Specific feedback';
|
||||
$string['started'] = 'Started';
|
||||
$string['state'] = 'State';
|
||||
$string['step'] = 'Step';
|
||||
$string['submissionoutofsequence'] = 'Access out of sequence. Please do not click the back button when working on quiz questions.';
|
||||
$string['submissionoutofsequencefriendlymessage'] = "You have entered data outside the normal sequence. This can occur if you use your browser's Back or Forward buttons; please don't use these during the test. It can also happen if you click on something while a page is loading. Click <strong>Continue</strong> to resume.";
|
||||
$string['submit'] = 'Submit';
|
||||
$string['submitandfinish'] = 'Submit and finish';
|
||||
$string['submitted'] = 'Submit: {$a}';
|
||||
$string['unknownquestion'] = 'Unknown question: {$a}.';
|
||||
$string['unknownquestioncatregory'] = 'Unknown question category: {$a}.';
|
||||
$string['whethercorrect'] = 'Whether correct';
|
||||
$string['withselected'] = 'With selected';
|
||||
$string['xoutofmax'] = '{$a->mark} out of {$a->max}';
|
||||
$string['yougotnright'] = 'You have correctly selected {$a->num}.';
|
||||
|
@ -99,6 +99,8 @@ $string['generalstructure'] = 'General structure';
|
||||
$string['checkusercapability'] = 'Check user capability';
|
||||
$string['checkusercapabilitydescription'] = 'The user should have appropriate capabilities according to the protocols used, for example webservice/rest:use, webservice/soap:use. To achieve this, create a web services role with protocol capabilities allowed and assign it to the web services user as a system role.';
|
||||
$string['information'] = 'Information';
|
||||
$string['installserviceshortnameerror'] = 'Coding error: the service shortname "{$a}" should have contains numbers, letters and _-.. only.';
|
||||
$string['installexistingserviceshortnameerror'] = 'A web service with the shortname "{$a}" already exists. Can not install/update a different web service with this shortname.';
|
||||
$string['invalidextparam'] = 'Invalid external api parameter: {$a}';
|
||||
$string['invalidextresponse'] = 'Invalid external api response: {$a}';
|
||||
$string['invalidiptoken'] = 'Invalid token - your IP is not supported';
|
||||
@ -115,6 +117,7 @@ $string['missingcaps'] = 'Missing capabilities';
|
||||
$string['missingcaps_help'] = 'List of required capabilities for the service which the selected user does not have. Missing capabilities must be added to the user\'s role in order to use the service.';
|
||||
$string['missingpassword'] = 'Missing password';
|
||||
$string['missingusername'] = 'Missing username';
|
||||
$string['missingversionfile'] = 'Coding error: version.php file is missing for the component {$a}';
|
||||
$string['nofunctions'] = 'This service has no functions.';
|
||||
$string['norequiredcapability'] = 'No required capability';
|
||||
$string['notoken'] = 'The token list is empty.';
|
||||
|
464
lib/adminlib.php
464
lib/adminlib.php
@ -107,6 +107,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
/// Add libraries
|
||||
require_once($CFG->libdir.'/ddllib.php');
|
||||
require_once($CFG->libdir.'/xmlize.php');
|
||||
require_once($CFG->libdir.'/messagelib.php');
|
||||
|
||||
define('INSECURE_DATAROOT_WARNING', 1);
|
||||
define('INSECURE_DATAROOT_ERROR', 2);
|
||||
@ -260,6 +261,14 @@ function uninstall_plugin($type, $name) {
|
||||
// delete the module configuration records
|
||||
unset_all_config_for_plugin($pluginname);
|
||||
|
||||
// delete message provider
|
||||
message_provider_uninstall($component);
|
||||
|
||||
// delete message processor
|
||||
if ($type === 'message') {
|
||||
message_processor_uninstall($name);
|
||||
}
|
||||
|
||||
// delete the plugin tables
|
||||
$xmldbfilepath = $plugindirectory . '/db/install.xml';
|
||||
drop_plugin_tables($pluginname, $xmldbfilepath, false);
|
||||
@ -3762,6 +3771,35 @@ class admin_setting_special_calendar_weekend extends admin_setting {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Admin setting that allows a user to pick a behaviour.
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class admin_setting_question_behaviour extends admin_setting_configselect {
|
||||
/**
|
||||
* @param string $name name of config variable
|
||||
* @param string $visiblename display name
|
||||
* @param string $description description
|
||||
* @param string $default default.
|
||||
*/
|
||||
public function __construct($name, $visiblename, $description, $default) {
|
||||
parent::__construct($name, $visiblename, $description, $default, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load list of behaviours as choices
|
||||
* @return bool true => success, false => error.
|
||||
*/
|
||||
public function load_choices() {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/question/engine/lib.php');
|
||||
$this->choices = question_engine::get_archetypal_behaviours();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Admin setting that allows a user to pick appropriate roles for something.
|
||||
*
|
||||
@ -4909,6 +4947,75 @@ class admin_page_manageblocks extends admin_externalpage {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Message outputs configuration
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class admin_page_managemessageoutputs extends admin_externalpage {
|
||||
/**
|
||||
* Calls parent::__construct with specific arguments
|
||||
*/
|
||||
public function __construct() {
|
||||
global $CFG;
|
||||
parent::__construct('managemessageoutputs', get_string('managemessageoutputs', 'message'), new moodle_url('/admin/message.php'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a specific message processor
|
||||
*
|
||||
* @param string $query The string to search for
|
||||
* @return array
|
||||
*/
|
||||
public function search($query) {
|
||||
global $CFG, $DB;
|
||||
if ($result = parent::search($query)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$found = false;
|
||||
if ($processors = get_message_processors()) {
|
||||
$textlib = textlib_get_instance();
|
||||
foreach ($processors as $processor) {
|
||||
if (!$processor->available) {
|
||||
continue;
|
||||
}
|
||||
if (strpos($processor->name, $query) !== false) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
$strprocessorname = get_string('pluginname', 'message_'.$processor->name);
|
||||
if (strpos($textlib->strtolower($strprocessorname), $query) !== false) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($found) {
|
||||
$result = new stdClass();
|
||||
$result->page = $this;
|
||||
$result->settings = array();
|
||||
return array($this->name => $result);
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default message outputs configuration
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class admin_page_defaultmessageoutputs extends admin_page_managemessageoutputs {
|
||||
/**
|
||||
* Calls parent::__construct with specific arguments
|
||||
*/
|
||||
public function __construct() {
|
||||
global $CFG;
|
||||
admin_externalpage::__construct('defaultmessageoutputs', get_string('defaultmessageoutputs', 'message'), new moodle_url('/message/defaultoutputs.php'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Question type manage page
|
||||
@ -4925,9 +5032,9 @@ class admin_page_manageqtypes extends admin_externalpage {
|
||||
}
|
||||
|
||||
/**
|
||||
* Search QTYPES for the specified string
|
||||
* Search question types for the specified string
|
||||
*
|
||||
* @param string $query The string to search for in QTYPES
|
||||
* @param string $query The string to search for in question types
|
||||
* @return array
|
||||
*/
|
||||
public function search($query) {
|
||||
@ -4938,9 +5045,8 @@ class admin_page_manageqtypes extends admin_externalpage {
|
||||
|
||||
$found = false;
|
||||
$textlib = textlib_get_instance();
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
global $QTYPES;
|
||||
foreach ($QTYPES as $qtype) {
|
||||
require_once($CFG->dirroot . '/question/engine/bank.php');
|
||||
foreach (question_bank::get_all_qtypes() as $qtype) {
|
||||
if (strpos($textlib->strtolower($qtype->local_name()), $query) !== false) {
|
||||
$found = true;
|
||||
break;
|
||||
@ -6381,6 +6487,162 @@ class admin_setting_managerepository extends admin_setting {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special checkbox for enable mobile web service
|
||||
* If enable then we store the service id of the mobile service into config table
|
||||
* If disable then we unstore the service id from the config table
|
||||
*/
|
||||
class admin_setting_enablemobileservice extends admin_setting_configcheckbox {
|
||||
|
||||
private $xmlrpcuse; //boolean: true => capability 'webservice/xmlrpc:use' is set for authenticated user role
|
||||
|
||||
/**
|
||||
* Return true if Authenticated user role has the capability 'webservice/xmlrpc:use', otherwise false
|
||||
* @return boolean
|
||||
*/
|
||||
private function is_xmlrpc_cap_allowed() {
|
||||
global $DB, $CFG;
|
||||
|
||||
//if the $this->xmlrpcuse variable is not set, it needs to be set
|
||||
if (empty($this->xmlrpcuse) and $this->xmlrpcuse!==false) {
|
||||
$params = array();
|
||||
$params['permission'] = CAP_ALLOW;
|
||||
$params['roleid'] = $CFG->defaultuserroleid;
|
||||
$params['capability'] = 'webservice/xmlrpc:use';
|
||||
$this->xmlrpcuse = $DB->record_exists('role_capabilities', $params);
|
||||
}
|
||||
|
||||
return $this->xmlrpcuse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the 'webservice/xmlrpc:use' to the Authenticated user role (allow or not)
|
||||
* @param type $status true to allow, false to not set
|
||||
*/
|
||||
private function set_xmlrpc_cap($status) {
|
||||
global $CFG;
|
||||
if ($status and !$this->is_xmlrpc_cap_allowed()) {
|
||||
//need to allow the cap
|
||||
$permission = CAP_ALLOW;
|
||||
$assign = true;
|
||||
} else if (!$status and $this->is_xmlrpc_cap_allowed()){
|
||||
//need to disallow the cap
|
||||
$permission = CAP_INHERIT;
|
||||
$assign = true;
|
||||
}
|
||||
if (!empty($assign)) {
|
||||
$systemcontext = get_system_context();
|
||||
assign_capability('webservice/xmlrpc:use', $permission, $CFG->defaultuserroleid, $systemcontext->id, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds XHTML to display the control.
|
||||
* The main purpose of this overloading is to display a warning when https
|
||||
* is not supported by the server
|
||||
* @param string $data Unused
|
||||
* @param string $query
|
||||
* @return string XHTML
|
||||
*/
|
||||
public function output_html($data, $query='') {
|
||||
global $CFG, $OUTPUT;
|
||||
$html = parent::output_html($data, $query);
|
||||
|
||||
if ((string)$data === $this->yes) {
|
||||
require_once($CFG->dirroot . "/lib/filelib.php");
|
||||
$curl = new curl();
|
||||
$httpswwwroot = str_replace('http:', 'https:', $CFG->wwwroot); //force https url
|
||||
$curl->head($httpswwwroot . "/login/index.php");
|
||||
$info = $curl->get_info();
|
||||
if (empty($info['http_code']) or ($info['http_code'] >= 400)) {
|
||||
$html .= $OUTPUT->notification(get_string('nohttpsformobilewarning', 'admin'));
|
||||
}
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current setting using the objects name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_setting() {
|
||||
global $CFG;
|
||||
$webservicesystem = $CFG->enablewebservices;
|
||||
require_once($CFG->dirroot . '/webservice/lib.php');
|
||||
$webservicemanager = new webservice();
|
||||
$mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
|
||||
if ($mobileservice->enabled and !empty($webservicesystem) and $this->is_xmlrpc_cap_allowed()) {
|
||||
return $this->config_read($this->name); //same as returning 1
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the selected setting
|
||||
*
|
||||
* @param string $data The selected site
|
||||
* @return string empty string or error message
|
||||
*/
|
||||
public function write_setting($data) {
|
||||
global $DB, $CFG;
|
||||
$servicename = MOODLE_OFFICIAL_MOBILE_SERVICE;
|
||||
|
||||
require_once($CFG->dirroot . '/webservice/lib.php');
|
||||
$webservicemanager = new webservice();
|
||||
|
||||
if ((string)$data === $this->yes) {
|
||||
//code run when enable mobile web service
|
||||
//enable web service systeme if necessary
|
||||
set_config('enablewebservices', true);
|
||||
|
||||
//enable mobile service
|
||||
$mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
|
||||
$mobileservice->enabled = 1;
|
||||
$webservicemanager->update_external_service($mobileservice);
|
||||
|
||||
//enable xml-rpc server
|
||||
$activeprotocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
|
||||
|
||||
if (!in_array('xmlrpc', $activeprotocols)) {
|
||||
$activeprotocols[] = 'xmlrpc';
|
||||
set_config('webserviceprotocols', implode(',', $activeprotocols));
|
||||
}
|
||||
|
||||
//allow xml-rpc:use capability for authenticated user
|
||||
$this->set_xmlrpc_cap(true);
|
||||
|
||||
} else {
|
||||
//disable web service system if no other services are enabled
|
||||
$otherenabledservices = $DB->get_records_select('external_services',
|
||||
'enabled = :enabled AND (shortname != :shortname OR shortname IS NULL)', array('enabled' => 1,
|
||||
'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE));
|
||||
if (empty($otherenabledservices)) {
|
||||
set_config('enablewebservices', false);
|
||||
|
||||
//also disable xml-rpc server
|
||||
$activeprotocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
|
||||
$protocolkey = array_search('xmlrpc', $activeprotocols);
|
||||
if ($protocolkey !== false) {
|
||||
unset($activeprotocols[$protocolkey]);
|
||||
set_config('webserviceprotocols', implode(',', $activeprotocols));
|
||||
}
|
||||
|
||||
//disallow xml-rpc:use capability for authenticated user
|
||||
$this->set_xmlrpc_cap(false);
|
||||
}
|
||||
|
||||
//disable the mobile service
|
||||
$mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
|
||||
$mobileservice->enabled = 0;
|
||||
$webservicemanager->update_external_service($mobileservice);
|
||||
}
|
||||
|
||||
return (parent::write_setting($data));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special class for management of external services
|
||||
@ -7307,9 +7569,199 @@ class admin_setting_configcolourpicker extends admin_setting {
|
||||
$content .= html_writer::end_tag('div');
|
||||
return format_admin_setting($this, $this->visiblename, $content, $this->description, false, '', $this->get_defaultsetting(), $query);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Administration interface for user specified regular expressions for device detection.
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class admin_setting_devicedetectregex extends admin_setting {
|
||||
|
||||
/**
|
||||
* Calls parent::__construct with specific args
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $visiblename
|
||||
* @param string $description
|
||||
* @param mixed $defaultsetting
|
||||
*/
|
||||
public function __construct($name, $visiblename, $description, $defaultsetting = '') {
|
||||
global $CFG;
|
||||
parent::__construct($name, $visiblename, $description, $defaultsetting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current setting(s)
|
||||
*
|
||||
* @return array Current settings array
|
||||
*/
|
||||
public function get_setting() {
|
||||
global $CFG;
|
||||
|
||||
$config = $this->config_read($this->name);
|
||||
if (is_null($config)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->prepare_form_data($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save selected settings
|
||||
*
|
||||
* @param array $data Array of settings to save
|
||||
* @return bool
|
||||
*/
|
||||
public function write_setting($data) {
|
||||
if (empty($data)) {
|
||||
$data = array();
|
||||
}
|
||||
|
||||
if ($this->config_write($this->name, $this->process_form_data($data))) {
|
||||
return ''; // success
|
||||
} else {
|
||||
return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return XHTML field(s) for regexes
|
||||
*
|
||||
* @param array $data Array of options to set in HTML
|
||||
* @return string XHTML string for the fields and wrapping div(s)
|
||||
*/
|
||||
public function output_html($data, $query='') {
|
||||
global $OUTPUT;
|
||||
|
||||
$out = html_writer::start_tag('table', array('border' => 1, 'class' => 'generaltable'));
|
||||
$out .= html_writer::start_tag('thead');
|
||||
$out .= html_writer::start_tag('tr');
|
||||
$out .= html_writer::tag('th', get_string('devicedetectregexexpression', 'admin'));
|
||||
$out .= html_writer::tag('th', get_string('devicedetectregexvalue', 'admin'));
|
||||
$out .= html_writer::end_tag('tr');
|
||||
$out .= html_writer::end_tag('thead');
|
||||
$out .= html_writer::start_tag('tbody');
|
||||
|
||||
if (empty($data)) {
|
||||
$looplimit = 1;
|
||||
} else {
|
||||
$looplimit = (count($data)/2)+1;
|
||||
}
|
||||
|
||||
for ($i=0; $i<$looplimit; $i++) {
|
||||
$out .= html_writer::start_tag('tr');
|
||||
|
||||
$expressionname = 'expression'.$i;
|
||||
|
||||
if (!empty($data[$expressionname])){
|
||||
$expression = $data[$expressionname];
|
||||
} else {
|
||||
$expression = '';
|
||||
}
|
||||
|
||||
$out .= html_writer::tag('td',
|
||||
html_writer::empty_tag('input',
|
||||
array(
|
||||
'type' => 'text',
|
||||
'class' => 'form-text',
|
||||
'name' => $this->get_full_name().'[expression'.$i.']',
|
||||
'value' => $expression,
|
||||
)
|
||||
), array('class' => 'c'.$i)
|
||||
);
|
||||
|
||||
$valuename = 'value'.$i;
|
||||
|
||||
if (!empty($data[$valuename])){
|
||||
$value = $data[$valuename];
|
||||
} else {
|
||||
$value= '';
|
||||
}
|
||||
|
||||
$out .= html_writer::tag('td',
|
||||
html_writer::empty_tag('input',
|
||||
array(
|
||||
'type' => 'text',
|
||||
'class' => 'form-text',
|
||||
'name' => $this->get_full_name().'[value'.$i.']',
|
||||
'value' => $value,
|
||||
)
|
||||
), array('class' => 'c'.$i)
|
||||
);
|
||||
|
||||
$out .= html_writer::end_tag('tr');
|
||||
}
|
||||
|
||||
$out .= html_writer::end_tag('tbody');
|
||||
$out .= html_writer::end_tag('table');
|
||||
|
||||
return format_admin_setting($this, $this->visiblename, $out, $this->description, false, '', null, $query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the string of regexes
|
||||
*
|
||||
* @see self::process_form_data()
|
||||
* @param $regexes string of regexes
|
||||
* @return array of form fields and their values
|
||||
*/
|
||||
protected function prepare_form_data($regexes) {
|
||||
|
||||
$regexes = json_decode($regexes);
|
||||
|
||||
$form = array();
|
||||
|
||||
$i = 0;
|
||||
|
||||
foreach ($regexes as $value => $regex) {
|
||||
$expressionname = 'expression'.$i;
|
||||
$valuename = 'value'.$i;
|
||||
|
||||
$form[$expressionname] = $regex;
|
||||
$form[$valuename] = $value;
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the data from admin settings form into a string of regexes
|
||||
*
|
||||
* @see self::prepare_form_data()
|
||||
* @param array $data array of admin form fields and values
|
||||
* @return false|string of regexes
|
||||
*/
|
||||
protected function process_form_data(array $form) {
|
||||
|
||||
$count = count($form); // number of form field values
|
||||
|
||||
if ($count % 2) {
|
||||
// we must get five fields per expression
|
||||
return false;
|
||||
}
|
||||
|
||||
$regexes = array();
|
||||
for ($i = 0; $i < $count / 2; $i++) {
|
||||
$expressionname = "expression".$i;
|
||||
$valuename = "value".$i;
|
||||
|
||||
$expression = trim($form['expression'.$i]);
|
||||
$value = trim($form['value'.$i]);
|
||||
|
||||
if (empty($expression)){
|
||||
continue;
|
||||
}
|
||||
|
||||
$regexes[$value] = $expression;
|
||||
}
|
||||
|
||||
$regexes = json_encode($regexes);
|
||||
|
||||
return $regexes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiselect for current modules
|
||||
|
@ -131,7 +131,7 @@ function cron_run() {
|
||||
plagiarism_cron();
|
||||
|
||||
mtrace("Starting quiz reports");
|
||||
if ($reports = $DB->get_records_select('quiz_report', "cron > 0 AND ((? - lastcron) > cron)", array($timenow))) {
|
||||
if ($reports = $DB->get_records_select('quiz_reports', "cron > 0 AND ((? - lastcron) > cron)", array($timenow))) {
|
||||
foreach ($reports as $report) {
|
||||
$cronfile = "$CFG->dirroot/mod/quiz/report/$report->name/cron.php";
|
||||
if (file_exists($cronfile)) {
|
||||
@ -143,7 +143,7 @@ function cron_run() {
|
||||
$pre_dbqueries = $DB->perf_get_queries();
|
||||
$pre_time = microtime(1);
|
||||
if ($cron_function()) {
|
||||
$DB->set_field('quiz_report', "lastcron", $timenow, array("id"=>$report->id));
|
||||
$DB->set_field('quiz_reports', "lastcron", $timenow, array("id"=>$report->id));
|
||||
}
|
||||
if (isset($pre_dbqueries)) {
|
||||
mtrace("... used " . ($DB->perf_get_queries() - $pre_dbqueries) . " dbqueries");
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="lib/db" VERSION="20110523" COMMENT="XMLDB file for core Moodle tables"
|
||||
<XMLDB PATH="lib/db" VERSION="20110526" COMMENT="XMLDB file for core Moodle tables"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
@ -1279,9 +1279,9 @@
|
||||
<FIELD NAME="questiontext" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="questiontextformat"/>
|
||||
<FIELD NAME="questiontextformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="questiontext" NEXT="generalfeedback"/>
|
||||
<FIELD NAME="generalfeedback" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="to store the question feedback" PREVIOUS="questiontextformat" NEXT="generalfeedbackformat"/>
|
||||
<FIELD NAME="generalfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="generalfeedback" NEXT="defaultgrade"/>
|
||||
<FIELD NAME="defaultgrade" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="true" DEFAULT="1" SEQUENCE="false" DECIMALS="7" PREVIOUS="generalfeedbackformat" NEXT="penalty"/>
|
||||
<FIELD NAME="penalty" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="false" DEFAULT="0.1" SEQUENCE="false" DECIMALS="7" PREVIOUS="defaultgrade" NEXT="qtype"/>
|
||||
<FIELD NAME="generalfeedbackformat" TYPE="int" LENGTH="2" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="generalfeedback" NEXT="defaultmark"/>
|
||||
<FIELD NAME="defaultmark" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="true" DEFAULT="1" SEQUENCE="false" DECIMALS="7" PREVIOUS="generalfeedbackformat" NEXT="penalty"/>
|
||||
<FIELD NAME="penalty" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="false" DEFAULT="0.3333333" SEQUENCE="false" DECIMALS="7" PREVIOUS="defaultmark" NEXT="qtype"/>
|
||||
<FIELD NAME="qtype" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false" PREVIOUS="penalty" NEXT="length"/>
|
||||
<FIELD NAME="length" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="1" SEQUENCE="false" PREVIOUS="qtype" NEXT="stamp"/>
|
||||
<FIELD NAME="stamp" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="length" NEXT="version"/>
|
||||
@ -1300,7 +1300,7 @@
|
||||
<KEY NAME="modifiedby" TYPE="foreign" FIELDS="modifiedby" REFTABLE="user" REFFIELDS="id" COMMENT="foreign (modifiedby) references user (id)" PREVIOUS="createdby"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="question_answers" COMMENT="Answers, with a fractional grade (0-1) and feedback" PREVIOUS="question" NEXT="question_attempts">
|
||||
<TABLE NAME="question_answers" COMMENT="Answers, with a fractional grade (0-1) and feedback" PREVIOUS="question" NEXT="question_hints">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="question"/>
|
||||
<FIELD NAME="question" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="answer"/>
|
||||
@ -1315,16 +1315,93 @@
|
||||
<KEY NAME="question" TYPE="foreign" FIELDS="question" REFTABLE="question" REFFIELDS="id" PREVIOUS="primary"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="question_attempts" COMMENT="Student attempts. This table gets extended by the modules" PREVIOUS="question_answers" NEXT="question_states">
|
||||
<TABLE NAME="question_hints" COMMENT="Stores the the part of the question definition that gives different feedback after each try in interactive and similar behaviours." PREVIOUS="question_answers" NEXT="question_usages">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="modulename"/>
|
||||
<FIELD NAME="modulename" TYPE="char" LENGTH="20" NOTNULL="true" DEFAULT="quiz" SEQUENCE="false" PREVIOUS="id"/>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="questionid"/>
|
||||
<FIELD NAME="questionid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" PREVIOUS="id" NEXT="hint"/>
|
||||
<FIELD NAME="hint" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="The text of the feedback to be given." PREVIOUS="questionid" NEXT="hintformat"/>
|
||||
<FIELD NAME="hintformat" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" DEFAULT="0" COMMENT="The format of the hint." PREVIOUS="hint" NEXT="shownumcorrect"/>
|
||||
<FIELD NAME="shownumcorrect" TYPE="int" LENGTH="1" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" COMMENT="Whether the feedback should include a message about how many things the student got right. This is only applicable to certain question types (for example matching or multiple choice multiple-response)." PREVIOUS="hintformat" NEXT="clearwrong"/>
|
||||
<FIELD NAME="clearwrong" TYPE="int" LENGTH="1" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" COMMENT="Whether any wrong choices should be cleared before the next try. Whether this is applicable, and what it means, depends on the question type, as with the shownumright option." PREVIOUS="shownumcorrect" NEXT="options"/>
|
||||
<FIELD NAME="options" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="A space for any other question-type specific options." PREVIOUS="clearwrong"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="questionid"/>
|
||||
<KEY NAME="questionid" TYPE="foreign" FIELDS="questionid" REFTABLE="question" REFFIELDS="id" PREVIOUS="primary"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="question_states" COMMENT="Stores user responses to an attempt, and percentage grades" PREVIOUS="question_attempts" NEXT="question_sessions">
|
||||
<TABLE NAME="question_usages" COMMENT="This table's main purpose it to assign a unique id to each attempt at a set of questions by some part of Moodle. A question usage is made up of a number of question_attempts." PREVIOUS="question_hints" NEXT="question_attempts">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="contextid"/>
|
||||
<FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Every question usage must be associated with some context." PREVIOUS="id" NEXT="component"/>
|
||||
<FIELD NAME="component" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="The plugin this attempt belongs to, e.g. 'mod_quiz', 'block_questionoftheday', 'filter_embedquestion'." PREVIOUS="contextid" NEXT="preferredbehaviour"/>
|
||||
<FIELD NAME="preferredbehaviour" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="The archetypal behaviour that should be used for question attempts in this usage." PREVIOUS="component"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="contextid"/>
|
||||
<KEY NAME="contextid" TYPE="foreign" FIELDS="contextid" REFTABLE="context" REFFIELDS="id" PREVIOUS="primary"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="question_attempts" COMMENT="Each row here corresponds to an attempt at one question, as part of a question_usage. A question_attempt will have some question_attempt_steps" PREVIOUS="question_usages" NEXT="question_attempt_steps">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="questionusageid"/>
|
||||
<FIELD NAME="questionusageid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Foreign key, references question_usages.id" PREVIOUS="id" NEXT="slot"/>
|
||||
<FIELD NAME="slot" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Used to number the questions in one attempt sequentially." PREVIOUS="questionusageid" NEXT="behaviour"/>
|
||||
<FIELD NAME="behaviour" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="The name of the question behaviour that is managing this question attempt." PREVIOUS="slot" NEXT="questionid"/>
|
||||
<FIELD NAME="questionid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="The id of the question being attempted. Foreign key references question.id." PREVIOUS="behaviour" NEXT="variant"/>
|
||||
<FIELD NAME="variant" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" DEFAULT="1" COMMENT="The variant of the qusetion being used." PREVIOUS="questionid" NEXT="maxmark"/>
|
||||
<FIELD NAME="maxmark" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="false" SEQUENCE="false" DECIMALS="7" COMMENT="The grade this question is marked out of in this attempt." PREVIOUS="variant" NEXT="minfraction"/>
|
||||
<FIELD NAME="minfraction" TYPE="number" LENGTH="12" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" DECIMALS="7" COMMENT="Some questions can award negative marks. This indicates the most negative mark that can be awarded, on the faction scale where the maximum positive mark is 1." PREVIOUS="maxmark" NEXT="flagged"/>
|
||||
<FIELD NAME="flagged" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether this question has been flagged within the attempt." PREVIOUS="minfraction" NEXT="questionsummary"/>
|
||||
<FIELD NAME="questionsummary" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="If this question uses randomisation, it should set this field to summarise what random version the student actually saw. This is a human-readable textual summary of the student's response which might, for example, be used in a report." PREVIOUS="flagged" NEXT="rightanswer"/>
|
||||
<FIELD NAME="rightanswer" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="This is a human-readable textual summary of the right answer to this question. Might be used, for example on the quiz preview, to help people who are testing the question. Or might be used in reports." PREVIOUS="questionsummary" NEXT="responsesummary"/>
|
||||
<FIELD NAME="responsesummary" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="This is a textual summary of the student's response (basically what you would expect to in the Quiz responses report)." PREVIOUS="rightanswer" NEXT="timemodified"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="The time this record was last changed." PREVIOUS="responsesummary"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="questionid"/>
|
||||
<KEY NAME="questionid" TYPE="foreign" FIELDS="questionid" REFTABLE="question" REFFIELDS="id" PREVIOUS="primary" NEXT="questionusageid"/>
|
||||
<KEY NAME="questionusageid" TYPE="foreign" FIELDS="questionusageid" REFTABLE="question_usages" REFFIELDS="id" PREVIOUS="questionid"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="questionusageid-slot" UNIQUE="true" FIELDS="questionusageid, slot"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="question_attempt_steps" COMMENT="Stores one step in in a question attempt. As well as the data here, the step will have some data in the question_attempt_step_data table." PREVIOUS="question_attempts" NEXT="question_attempt_step_data">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="questionattemptid"/>
|
||||
<FIELD NAME="questionattemptid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Foreign key, references question_attempt.id" PREVIOUS="id" NEXT="sequencenumber"/>
|
||||
<FIELD NAME="sequencenumber" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Numbers the steps in a question attempt sequentially." PREVIOUS="questionattemptid" NEXT="state"/>
|
||||
<FIELD NAME="state" TYPE="char" LENGTH="13" NOTNULL="true" SEQUENCE="false" COMMENT="One of the constants defined by the question_state class, giving the state of the question at the end of this step." PREVIOUS="sequencenumber" NEXT="fraction"/>
|
||||
<FIELD NAME="fraction" TYPE="number" LENGTH="12" NOTNULL="false" UNSIGNED="false" SEQUENCE="false" DECIMALS="7" COMMENT="The grade for this question, when graded out of 1. Needs to be multiplied by question_attempt.maxmark to get the actual mark for the question." PREVIOUS="state" NEXT="timecreated"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Time-stamp of the action that lead to this state being created." PREVIOUS="fraction" NEXT="userid"/>
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" COMMENT="The user whose action lead to this state being created." PREVIOUS="timecreated"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="questionattemptid"/>
|
||||
<KEY NAME="questionattemptid" TYPE="foreign" FIELDS="questionattemptid" REFTABLE="question_attempts" REFFIELDS="id" PREVIOUS="primary" NEXT="userid"/>
|
||||
<KEY NAME="userid" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id" PREVIOUS="questionattemptid"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="questionattemptid-sequencenumber" UNIQUE="true" FIELDS="questionattemptid, sequencenumber"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="question_attempt_step_data" COMMENT="Each question_attempt_step has an associative array of the data that was submitted by the user in the POST request. It can also contain extra data from the question type or behaviour to avoid re-computation. The convention is that names belonging to the behaviour start with -, and cached values added to the submitted data start with _, or _-" PREVIOUS="question_attempt_steps" NEXT="question_states">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="attemptstepid"/>
|
||||
<FIELD NAME="attemptstepid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="Foreign key, references question_attempt_steps.id" PREVIOUS="id" NEXT="name"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="The name of this bit of data." PREVIOUS="attemptstepid" NEXT="value"/>
|
||||
<FIELD NAME="value" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" COMMENT="The corresponding value" PREVIOUS="name"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="attemptstepid"/>
|
||||
<KEY NAME="attemptstepid" TYPE="foreign" FIELDS="attemptstepid" REFTABLE="question_attempt_steps" REFFIELDS="id" PREVIOUS="primary"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="attemptstepid-name" UNIQUE="true" FIELDS="attemptstepid, name"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="question_states" COMMENT="Stores user responses to an attempt, and percentage grades" PREVIOUS="question_attempt_step_data" NEXT="question_sessions">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="attempt"/>
|
||||
<FIELD NAME="attempt" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="question"/>
|
||||
@ -2220,8 +2297,9 @@
|
||||
</TABLE>
|
||||
<TABLE NAME="message_processors" COMMENT="List of message output plugins" PREVIOUS="message_providers" NEXT="message_working">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="true" COMMENT="id of the table, please edit me" NEXT="name"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="166" NOTNULL="true" SEQUENCE="false" COMMENT="Default comment for the field, please edit me" PREVIOUS="id"/>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" SEQUENCE="true" NEXT="name"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="166" NOTNULL="true" SEQUENCE="false" COMMENT="Name of the message processor" PREVIOUS="id" NEXT="enabled"/>
|
||||
<FIELD NAME="enabled" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="true" DEFAULT="1" SEQUENCE="false" COMMENT="Defines if processor is enabled" PREVIOUS="name"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="primary key of the table, please edit me"/>
|
||||
@ -2484,7 +2562,8 @@
|
||||
<FIELD NAME="restrictedusers" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" PREVIOUS="requiredcapability" NEXT="component"/>
|
||||
<FIELD NAME="component" TYPE="char" LENGTH="100" NOTNULL="false" SEQUENCE="false" PREVIOUS="restrictedusers" NEXT="timecreated"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" PREVIOUS="component" NEXT="timemodified"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" PREVIOUS="timecreated"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" PREVIOUS="timecreated" NEXT="shortname"/>
|
||||
<FIELD NAME="shortname" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="a unique shortname" PREVIOUS="timemodified"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
|
@ -39,6 +39,10 @@ $messageproviders = array (
|
||||
),
|
||||
|
||||
'instantmessage' => array (
|
||||
'defaults' => array(
|
||||
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
|
||||
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDOFF,
|
||||
),
|
||||
),
|
||||
|
||||
'backup' => array (
|
||||
|
@ -206,4 +206,48 @@ $functions = array(
|
||||
'capabilities'=> 'moodle/course:create,moodle/course:visibility',
|
||||
),
|
||||
|
||||
// === message related functions ===
|
||||
|
||||
'moodle_message_send_messages' => array(
|
||||
'classname' => 'moodle_message_external',
|
||||
'methodname' => 'send_messages',
|
||||
'classpath' => 'message/externallib.php',
|
||||
'description' => 'Send messages',
|
||||
'type' => 'write',
|
||||
'capabilities'=> 'moodle/site:sendmessage',
|
||||
),
|
||||
|
||||
// === notes related functions ===
|
||||
|
||||
'moodle_notes_create_notes' => array(
|
||||
'classname' => 'moodle_notes_external',
|
||||
'methodname' => 'create_notes',
|
||||
'classpath' => 'notes/externallib.php',
|
||||
'description' => 'Create notes',
|
||||
'type' => 'write',
|
||||
'capabilities'=> 'moodle/notes:manage',
|
||||
),
|
||||
|
||||
// === webservice related functions ===
|
||||
|
||||
'moodle_webservice_get_siteinfo' => array(
|
||||
'classname' => 'moodle_webservice_external',
|
||||
'methodname' => 'get_siteinfo',
|
||||
'classpath' => 'webservice/externallib.php',
|
||||
'description' => 'Return some site info / user info / list web service functions',
|
||||
'type' => 'read',
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
$services = array(
|
||||
'Moodle mobile web service' => array(
|
||||
'functions' => array (
|
||||
'moodle_enrol_get_users_courses',
|
||||
'moodle_enrol_get_enrolled_users',
|
||||
'moodle_user_get_users_by_id'),
|
||||
'enabled' => 0,
|
||||
'restrictedusers' => 0,
|
||||
'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE
|
||||
),
|
||||
);
|
||||
|
@ -6112,6 +6112,438 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL");
|
||||
upgrade_main_savepoint(true, 2011052300.02);
|
||||
}
|
||||
|
||||
// Question engine 2 changes (14) start here
|
||||
if ($oldversion < 2011060300) {
|
||||
// Changing the default of field penalty on table question to 0.3333333
|
||||
$table = new xmldb_table('question');
|
||||
$field = new xmldb_field('penalty');
|
||||
$field->set_attributes(XMLDB_TYPE_NUMBER, '12, 7', null,
|
||||
XMLDB_NOTNULL, null, '0.3333333');
|
||||
|
||||
// Launch change of default for field penalty
|
||||
$dbman->change_field_default($table, $field);
|
||||
|
||||
// quiz savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060300);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060301) {
|
||||
|
||||
// Rename field defaultgrade on table question to defaultmark
|
||||
$table = new xmldb_table('question');
|
||||
$field = new xmldb_field('defaultgrade');
|
||||
$field->set_attributes(XMLDB_TYPE_NUMBER, '12, 7', null,
|
||||
XMLDB_NOTNULL, null, '1');
|
||||
|
||||
// Launch rename field defaultmark
|
||||
if ($dbman->field_exists($table, $field)) {
|
||||
$dbman->rename_field($table, $field, 'defaultmark');
|
||||
}
|
||||
|
||||
// quiz savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060301);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060302) {
|
||||
|
||||
// Rename the question_attempts table to question_usages.
|
||||
$table = new xmldb_table('question_attempts');
|
||||
if (!$dbman->table_exists('question_usages')) {
|
||||
$dbman->rename_table($table, 'question_usages');
|
||||
}
|
||||
|
||||
// quiz savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060302);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060303) {
|
||||
|
||||
// Rename the modulename field to component ...
|
||||
$table = new xmldb_table('question_usages');
|
||||
$field = new xmldb_field('modulename');
|
||||
$field->set_attributes(XMLDB_TYPE_CHAR, '255', null,
|
||||
XMLDB_NOTNULL, null, null, 'contextid');
|
||||
|
||||
if ($dbman->field_exists($table, $field)) {
|
||||
$dbman->rename_field($table, $field, 'component');
|
||||
}
|
||||
|
||||
// ... and update its contents.
|
||||
$DB->set_field('question_usages', 'component', 'mod_quiz', array('component' => 'quiz'));
|
||||
|
||||
// Add the contextid field.
|
||||
$field = new xmldb_field('contextid');
|
||||
$field->set_attributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
null, null, null, 'id');
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
|
||||
// And populate it.
|
||||
$quizmoduleid = $DB->get_field('modules', 'id', array('name' => 'quiz'));
|
||||
$DB->execute("
|
||||
UPDATE {question_usages} SET contextid = (
|
||||
SELECT ctx.id
|
||||
FROM {context} ctx
|
||||
JOIN {course_modules} cm ON cm.id = ctx.instanceid AND cm.module = $quizmoduleid
|
||||
JOIN {quiz_attempts} quiza ON quiza.quiz = cm.instance
|
||||
WHERE ctx.contextlevel = " . CONTEXT_MODULE . "
|
||||
AND quiza.uniqueid = {question_usages}.id
|
||||
)
|
||||
");
|
||||
|
||||
// Then make it NOT NULL.
|
||||
$field = new xmldb_field('contextid');
|
||||
$field->set_attributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, null, null, 'id');
|
||||
$dbman->change_field_notnull($table, $field);
|
||||
}
|
||||
|
||||
// Add the preferredbehaviour column. Populate it with a dummy value
|
||||
// for now. We will fill in the appropriate behaviour name when
|
||||
// updating all the rest of the attempt data.
|
||||
$field = new xmldb_field('preferredbehaviour');
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$field->set_attributes(XMLDB_TYPE_CHAR, '32', null,
|
||||
XMLDB_NOTNULL, null, 'to_be_set_later', 'component');
|
||||
$dbman->add_field($table, $field);
|
||||
|
||||
// Then remove the default value, now the column is populated.
|
||||
$field = new xmldb_field('preferredbehaviour');
|
||||
$field->set_attributes(XMLDB_TYPE_CHAR, '32', null,
|
||||
XMLDB_NOTNULL, null, null, 'component');
|
||||
$dbman->change_field_default($table, $field);
|
||||
}
|
||||
|
||||
// quiz savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060303);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060304) {
|
||||
|
||||
// Define key contextid (foreign) to be added to question_usages
|
||||
$table = new xmldb_table('question_usages');
|
||||
$key = new XMLDBKey('contextid');
|
||||
$key->set_attributes(XMLDB_KEY_FOREIGN, array('contextid'), 'context', array('id'));
|
||||
|
||||
// Launch add key contextid
|
||||
$dbman->add_key($table, $key);
|
||||
|
||||
// quiz savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060304);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060305) {
|
||||
|
||||
// Changing precision of field component on table question_usages to (255)
|
||||
// This was missed during the upgrade from old versions.
|
||||
$table = new xmldb_table('question_usages');
|
||||
$field = new xmldb_field('component');
|
||||
$field->set_attributes(XMLDB_TYPE_CHAR, '255', null,
|
||||
XMLDB_NOTNULL, null, null, 'contextid');
|
||||
|
||||
// Launch change of precision for field component
|
||||
$dbman->change_field_precision($table, $field);
|
||||
|
||||
// quiz savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060305);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060306) {
|
||||
|
||||
// Define table question_attempts to be created
|
||||
$table = new xmldb_table('question_attempts');
|
||||
if (!$dbman->table_exists($table)) {
|
||||
|
||||
// Adding fields to table question_attempts
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('questionusageid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('slot', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('behaviour', XMLDB_TYPE_CHAR, '32', null,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('questionid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('maxmark', XMLDB_TYPE_NUMBER, '12, 7', null,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('minfraction', XMLDB_TYPE_NUMBER, '12, 7', null,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('flagged', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, null, '0');
|
||||
$table->add_field('questionsummary', XMLDB_TYPE_TEXT, 'small', null,
|
||||
null, null, null);
|
||||
$table->add_field('rightanswer', XMLDB_TYPE_TEXT, 'small', null,
|
||||
null, null, null);
|
||||
$table->add_field('responsesummary', XMLDB_TYPE_TEXT, 'small', null,
|
||||
null, null, null);
|
||||
$table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
|
||||
// Adding keys to table question_attempts
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$table->add_key('questionid', XMLDB_KEY_FOREIGN, array('questionid'),
|
||||
'question', array('id'));
|
||||
$table->add_key('questionusageid', XMLDB_KEY_FOREIGN, array('questionusageid'),
|
||||
'question_usages', array('id'));
|
||||
|
||||
// Adding indexes to table question_attempts
|
||||
$table->add_index('questionusageid-slot', XMLDB_INDEX_UNIQUE,
|
||||
array('questionusageid', 'slot'));
|
||||
|
||||
// Launch create table for question_attempts
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
// quiz savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060306);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060307) {
|
||||
|
||||
// Define table question_attempt_steps to be created
|
||||
$table = new xmldb_table('question_attempt_steps');
|
||||
if (!$dbman->table_exists($table)) {
|
||||
|
||||
// Adding fields to table question_attempt_steps
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('questionattemptid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('sequencenumber', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('state', XMLDB_TYPE_CHAR, '13', null,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('fraction', XMLDB_TYPE_NUMBER, '12, 7', null,
|
||||
null, null, null);
|
||||
$table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('userid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
null, null, null);
|
||||
|
||||
// Adding keys to table question_attempt_steps
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$table->add_key('questionattemptid', XMLDB_KEY_FOREIGN,
|
||||
array('questionattemptid'), 'question_attempts_new', array('id'));
|
||||
$table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'),
|
||||
'user', array('id'));
|
||||
|
||||
// Adding indexes to table question_attempt_steps
|
||||
$table->add_index('questionattemptid-sequencenumber', XMLDB_INDEX_UNIQUE,
|
||||
array('questionattemptid', 'sequencenumber'));
|
||||
|
||||
// Launch create table for question_attempt_steps
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
// quiz savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060307);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060308) {
|
||||
|
||||
// Define table question_attempt_step_data to be created
|
||||
$table = new xmldb_table('question_attempt_step_data');
|
||||
if (!$dbman->table_exists($table)) {
|
||||
|
||||
// Adding fields to table question_attempt_step_data
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('attemptstepid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('name', XMLDB_TYPE_CHAR, '32', null,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('value', XMLDB_TYPE_TEXT, 'small', null,
|
||||
null, null, null);
|
||||
|
||||
// Adding keys to table question_attempt_step_data
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$table->add_key('attemptstepid', XMLDB_KEY_FOREIGN, array('attemptstepid'),
|
||||
'question_attempt_steps', array('id'));
|
||||
|
||||
// Adding indexes to table question_attempt_step_data
|
||||
$table->add_index('attemptstepid-name', XMLDB_INDEX_UNIQUE,
|
||||
array('attemptstepid', 'name'));
|
||||
|
||||
// Launch create table for question_attempt_step_data
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
// quiz savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060308);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060309) {
|
||||
|
||||
// Define table question_hints to be created
|
||||
$table = new xmldb_table('question_hints');
|
||||
|
||||
// Adding fields to table question_hints
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
|
||||
$table->add_field('questionid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('hint', XMLDB_TYPE_TEXT, 'small', null,
|
||||
XMLDB_NOTNULL, null, null);
|
||||
$table->add_field('hintformat', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, null, '0');
|
||||
$table->add_field('shownumcorrect', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED,
|
||||
null, null, null);
|
||||
$table->add_field('clearwrong', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED,
|
||||
null, null, null);
|
||||
$table->add_field('options', XMLDB_TYPE_CHAR, '255', null,
|
||||
null, null, null);
|
||||
|
||||
// Adding keys to table question_hints
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$table->add_key('questionid', XMLDB_KEY_FOREIGN, array('questionid'),
|
||||
'question', array('id'));
|
||||
|
||||
// Conditionally launch create table for question_hints
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
// quiz savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060309);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060310) {
|
||||
|
||||
// In the past, question_answer fractions were stored with rather
|
||||
// sloppy rounding. Now update them to the new standard of 7 d.p.
|
||||
$changes = array(
|
||||
'-0.66666' => '-0.6666667',
|
||||
'-0.33333' => '-0.3333333',
|
||||
'-0.16666' => '-0.1666667',
|
||||
'-0.142857' => '-0.1428571',
|
||||
'0.11111' => '0.1111111',
|
||||
'0.142857' => '0.1428571',
|
||||
'0.16666' => '0.1666667',
|
||||
'0.33333' => '0.3333333',
|
||||
'0.333333' => '0.3333333',
|
||||
'0.66666' => '0.6666667',
|
||||
);
|
||||
foreach ($changes as $from => $to) {
|
||||
$DB->set_field('question_answers',
|
||||
'fraction', $to, array('fraction' => $from));
|
||||
}
|
||||
|
||||
// quiz savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060310);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060311) {
|
||||
|
||||
// In the past, question penalties were stored with rather
|
||||
// sloppy rounding. Now update them to the new standard of 7 d.p.
|
||||
$DB->set_field('question',
|
||||
'penalty', 0.3333333, array('penalty' => 33.3));
|
||||
$DB->set_field_select('question',
|
||||
'penalty', 0.3333333, 'penalty >= 0.33 AND penalty <= 0.34');
|
||||
$DB->set_field_select('question',
|
||||
'penalty', 0.6666667, 'penalty >= 0.66 AND penalty <= 0.67');
|
||||
$DB->set_field_select('question',
|
||||
'penalty', 1, 'penalty > 1');
|
||||
|
||||
// quiz savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060311);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060312) {
|
||||
|
||||
// Define field hintformat to be added to question_hints table.
|
||||
$table = new xmldb_table('question_hints');
|
||||
$field = new xmldb_field('hintformat', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, null, '0');
|
||||
|
||||
// Conditionally launch add field partiallycorrectfeedbackformat
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
upgrade_main_savepoint(true, 2011060312);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060313) {
|
||||
// Define field variant to be added to question_attempts
|
||||
$table = new xmldb_table('question_attempts');
|
||||
$field = new xmldb_field('variant', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
|
||||
XMLDB_NOTNULL, null, 1, 'questionid');
|
||||
|
||||
// Launch add field component
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Main savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060313);
|
||||
}
|
||||
// Question engine 2 changes (14) end here
|
||||
|
||||
if ($oldversion < 2011060500) {
|
||||
|
||||
// Define index uniqueuserrating (not unique) to be dropped from rating
|
||||
$table = new xmldb_table('rating');
|
||||
$index = new xmldb_index('uniqueuserrating', XMLDB_INDEX_NOTUNIQUE,
|
||||
array('component', 'ratingarea', 'contextid', 'itemid'));
|
||||
|
||||
// Drop dependent index before changing fields specs
|
||||
if ($dbman->index_exists($table, $index)) {
|
||||
$dbman->drop_index($table, $index);
|
||||
}
|
||||
|
||||
// Changing the default of field component on table rating to drop it
|
||||
$field = new xmldb_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'contextid');
|
||||
|
||||
// Launch change of default for field component
|
||||
$dbman->change_field_default($table, $field);
|
||||
|
||||
// Changing the default of field ratingarea on table rating to drop it
|
||||
$field = new xmldb_field('ratingarea', XMLDB_TYPE_CHAR, '50', null, XMLDB_NOTNULL, null, null, 'component');
|
||||
|
||||
// Launch change of default for field ratingarea
|
||||
$dbman->change_field_default($table, $field);
|
||||
|
||||
// Add dependent index back
|
||||
if (!$dbman->index_exists($table, $index)) {
|
||||
$dbman->add_index($table, $index);
|
||||
}
|
||||
|
||||
// Main savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060500);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060800) {
|
||||
// Add enabled field to message_processors
|
||||
$table = new xmldb_table('message_processors');
|
||||
$field = new xmldb_field('enabled');
|
||||
$field->set_attributes(XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '1', 'name');
|
||||
|
||||
// Launch add field addition
|
||||
if (!$dbman->field_exists($table,$field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Populate default messaging settings
|
||||
upgrade_populate_default_messaging_prefs();
|
||||
|
||||
upgrade_main_savepoint(true, 2011060800);
|
||||
}
|
||||
|
||||
if ($oldversion < 2011060800.01) { //TODO: put the right latest version
|
||||
// Define field shortname to be added to external_services
|
||||
$table = new xmldb_table('external_services');
|
||||
$field = new xmldb_field('shortname', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'timemodified');
|
||||
|
||||
// Conditionally launch add field shortname
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Main savepoint reached
|
||||
upgrade_main_savepoint(true, 2011060800.01);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -645,3 +645,54 @@ function update_fix_automated_backup_config() {
|
||||
unset_config('backup_sche_gradebook_history');
|
||||
unset_config('disablescheduleddbackups');
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used to set default messaging preferences when the new
|
||||
* admin-level messaging defaults settings have been introduced.
|
||||
*/
|
||||
function upgrade_populate_default_messaging_prefs() {
|
||||
global $DB;
|
||||
|
||||
$providers = $DB->get_records('message_providers');
|
||||
$processors = $DB->get_records('message_processors');
|
||||
$defaultpreferences = (object)$DB->get_records_menu('config_plugins', array('plugin'=>'message'), '', 'name,value');
|
||||
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
|
||||
$setting = new stdClass();
|
||||
$setting->plugin = 'message';
|
||||
|
||||
foreach ($providers as $provider) {
|
||||
$componentproviderbase = $provider->component.'_'.$provider->name;
|
||||
// set MESSAGE_PERMITTED to all combinations of message types
|
||||
// (providers) and outputs (processors)
|
||||
foreach ($processors as $processor) {
|
||||
$preferencename = $processor->name.'_provider_'.$componentproviderbase.'_permitted';
|
||||
if (!isset($defaultpreferences->{$preferencename})) {
|
||||
$setting->name = $preferencename;
|
||||
$setting->value = 'permitted';
|
||||
$DB->insert_record('config_plugins', $setting);
|
||||
}
|
||||
}
|
||||
// for email output we also have to set MESSAGE_DEFAULT_OFFLINE + MESSAGE_DEFAULT_ONLINE
|
||||
foreach(array('loggedin', 'loggedoff') as $state) {
|
||||
$preferencename = 'message_provider_'.$componentproviderbase.'_'.$state;
|
||||
if (!isset($defaultpreferences->{$preferencename})) {
|
||||
$setting->name = $preferencename;
|
||||
$setting->value = 'email';
|
||||
// except instant message where default for popup should be
|
||||
// MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF and for email
|
||||
// MESSAGE_DEFAULT_LOGGEDOFF.
|
||||
if ($componentproviderbase == 'moodle_instantmessage') {
|
||||
if ($state == 'loggedoff') {
|
||||
$setting->value = 'email,popup';
|
||||
} else {
|
||||
$setting->value = 'popup';
|
||||
}
|
||||
}
|
||||
$DB->insert_record('config_plugins', $setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
$transaction->allow_commit();
|
||||
}
|
||||
|
@ -169,6 +169,7 @@ class html2text
|
||||
'/&(bull|#149|#8226);/i', // Bullet
|
||||
'/&(pound|#163);/i', // Pound sign
|
||||
'/&(euro|#8364);/i', // Euro sign
|
||||
'/[ ]+([\n\t])/', // Trailing spaces before newline or tab
|
||||
'/[ ]{2,}/' // Runs of spaces, post-handling
|
||||
);
|
||||
|
||||
@ -212,6 +213,7 @@ class html2text
|
||||
'*',
|
||||
'£',
|
||||
'EUR', // Euro sign. € ?
|
||||
'\\1', // Trailing spaces before newline or tab
|
||||
' ' // Runs of spaces, post-handling
|
||||
);
|
||||
|
||||
|
@ -574,7 +574,6 @@ function install_cli_database(array $options, $interactive) {
|
||||
$admins = get_admins();
|
||||
$admin = reset($admins);
|
||||
session_set_user($admin);
|
||||
message_set_default_message_preferences($admin);
|
||||
|
||||
// apply all default settings, do it twice to fill all defaults - some settings depend on other setting
|
||||
admin_apply_default_settings(NULL, true);
|
||||
|
@ -26,6 +26,8 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(dirname(dirname(__FILE__)) . '/message/lib.php');
|
||||
|
||||
/**
|
||||
* Called when a message provider wants to send a message.
|
||||
* This functions checks the user's processor configuration to send the given type of message,
|
||||
@ -34,8 +36,8 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* Required parameter $eventdata structure:
|
||||
* component string component name. must exist in message_providers
|
||||
* name string message type name. must exist in message_providers
|
||||
* userfrom object the user sending the message
|
||||
* userto object the message recipient
|
||||
* userfrom object|int the user sending the message
|
||||
* userto object|int the message recipient
|
||||
* subject string the message subject
|
||||
* fullmessage - the full message in a given format
|
||||
* fullmessageformat - the format if the full message (FORMAT_MOODLE, FORMAT_HTML, ..)
|
||||
@ -57,12 +59,10 @@ function message_send($eventdata) {
|
||||
$DB->transactions_forbidden();
|
||||
|
||||
if (is_int($eventdata->userto)) {
|
||||
mtrace('message_send() userto is a user ID when it should be a user object');
|
||||
$eventdata->userto = $DB->get_record('user', array('id' => $eventdata->useridto));
|
||||
$eventdata->userto = $DB->get_record('user', array('id' => $eventdata->userto));
|
||||
}
|
||||
if (is_int($eventdata->userfrom)) {
|
||||
mtrace('message_send() userfrom is a user ID when it should be a user object');
|
||||
$eventdata->userfrom = $DB->get_record('user', array('id' => $message->userfrom));
|
||||
$eventdata->userfrom = $DB->get_record('user', array('id' => $eventdata->userfrom));
|
||||
}
|
||||
|
||||
//after how long inactive should the user be considered logged off?
|
||||
@ -109,25 +109,55 @@ function message_send($eventdata) {
|
||||
|
||||
$savemessage->timecreated = time();
|
||||
|
||||
// Find out what processors are defined currently
|
||||
// When a user doesn't have settings none gets return, if he doesn't want contact "" gets returned
|
||||
$preferencename = 'message_provider_'.$eventdata->component.'_'.$eventdata->name.'_'.$userstate;
|
||||
// Fetch enabled processors
|
||||
$processors = get_message_processors(true);
|
||||
// Fetch default (site) preferences
|
||||
$defaultpreferences = get_message_output_default_preferences();
|
||||
|
||||
$processor = get_user_preferences($preferencename, null, $eventdata->userto->id);
|
||||
if ($processor == NULL) { //this user never had a preference, save default
|
||||
if (!message_set_default_message_preferences($eventdata->userto)) {
|
||||
print_error('cannotsavemessageprefs', 'message');
|
||||
}
|
||||
$processor = get_user_preferences($preferencename, NULL, $eventdata->userto->id);
|
||||
if (empty($processor)) {
|
||||
// Preset variables
|
||||
$processorlist = array();
|
||||
$preferencebase = $eventdata->component.'_'.$eventdata->name;
|
||||
// Fill in the array of processors to be used based on default and user preferences
|
||||
foreach ($processors as $processor) {
|
||||
// First find out permissions
|
||||
$defaultpreference = $processor->name.'_provider_'.$preferencebase.'_permitted';
|
||||
if (isset($defaultpreferences->{$defaultpreference})) {
|
||||
$permitted = $defaultpreferences->{$defaultpreference};
|
||||
} else {
|
||||
//MDL-25114 They supplied an $eventdata->component $eventdata->name combination which doesn't
|
||||
//exist in the message_provider table
|
||||
//exist in the message_provider table (thus there is no default settings for them)
|
||||
$preferrormsg = get_string('couldnotfindpreference', 'message', $preferencename);
|
||||
throw new coding_exception($preferrormsg,'blah');
|
||||
}
|
||||
|
||||
// Find out if user has configured this output
|
||||
$userisconfigured = $processor->object->is_user_configured($eventdata->userto);
|
||||
|
||||
// DEBUG: noify if we are forcing unconfigured output
|
||||
if ($permitted == 'forced' && !$userisconfigured) {
|
||||
debugging('Attempt to force message delivery to user who has "'.$processor->name.'" output unconfigured', DEBUG_NORMAL);
|
||||
}
|
||||
|
||||
if ($processor=='none' && $savemessage->notification) {
|
||||
// Populate the list of processors we will be using
|
||||
if ($permitted == 'forced' && $userisconfigured) {
|
||||
// We force messages for this processor, so use this processor unconditionally if user has configured it
|
||||
$processorlist[] = $processor->name;
|
||||
} else if ($permitted == 'permitted' && $userisconfigured) {
|
||||
// User settings are permitted, see if user set any, otherwise use site default ones
|
||||
$userpreferencename = 'message_provider_'.$preferencebase.'_'.$userstate;
|
||||
if ($userpreference = get_user_preferences($userpreferencename, null, $eventdata->userto->id)) {
|
||||
if (in_array($processor->name, explode(',', $userpreference))) {
|
||||
$processorlist[] = $processor->name;
|
||||
}
|
||||
} else if (isset($defaultpreferences->{$userpreferencename})) {
|
||||
if (in_array($processor->name, explode(',', $defaultpreferences->{$userpreferencename}))) {
|
||||
$processorlist[] = $processor->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($processorlist) && $savemessage->notification) {
|
||||
//if they have deselected all processors and its a notification mark it read. The user doesnt want to be bothered
|
||||
$savemessage->timeread = time();
|
||||
$messageid = $DB->insert_record('message_read', $savemessage);
|
||||
@ -137,28 +167,13 @@ function message_send($eventdata) {
|
||||
$eventdata->savedmessageid = $savemessage->id;
|
||||
|
||||
// Try to deliver the message to each processor
|
||||
if ($processor!='none') {
|
||||
$processorlist = explode(',', $processor);
|
||||
if (!empty($processorlist)) {
|
||||
foreach ($processorlist as $procname) {
|
||||
$processorfile = $CFG->dirroot. '/message/output/'.$procname.'/message_output_'.$procname.'.php';
|
||||
|
||||
if (is_readable($processorfile)) {
|
||||
include_once($processorfile); // defines $module with version etc
|
||||
$processclass = 'message_output_' . $procname;
|
||||
|
||||
if (class_exists($processclass)) {
|
||||
$pclass = new $processclass();
|
||||
|
||||
if (!$pclass->send_message($eventdata)) {
|
||||
if (!$processors[$procname]->object->send_message($eventdata)) {
|
||||
debugging('Error calling message processor '.$procname);
|
||||
$messageid = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debugging('Error finding message processor '.$procname);
|
||||
$messageid = false;
|
||||
}
|
||||
}
|
||||
|
||||
//if messaging is disabled and they previously had forum notifications handled by the popup processor
|
||||
//or any processor that puts a row in message_working then the notification will remain forever
|
||||
@ -180,6 +195,7 @@ function message_send($eventdata) {
|
||||
|
||||
/**
|
||||
* This code updates the message_providers table with the current set of providers
|
||||
*
|
||||
* @param $component - examples: 'moodle', 'mod_forum', 'block_quiz_results'
|
||||
* @return boolean
|
||||
*/
|
||||
@ -195,7 +211,7 @@ function message_update_providers($component='moodle') {
|
||||
foreach ($fileproviders as $messagename => $fileprovider) {
|
||||
|
||||
if (!empty($dbproviders[$messagename])) { // Already exists in the database
|
||||
|
||||
// check if capability has changed
|
||||
if ($dbproviders[$messagename]->capability == $fileprovider['capability']) { // Same, so ignore
|
||||
// exact same message provider already present in db, ignore this entry
|
||||
unset($dbproviders[$messagename]);
|
||||
@ -217,19 +233,128 @@ function message_update_providers($component='moodle') {
|
||||
$provider->component = $component;
|
||||
$provider->capability = $fileprovider['capability'];
|
||||
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
$DB->insert_record('message_providers', $provider);
|
||||
message_set_default_message_preference($component, $messagename, $fileprovider);
|
||||
$transaction->allow_commit();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($dbproviders as $dbprovider) { // Delete old ones
|
||||
$DB->delete_records('message_providers', array('id' => $dbprovider->id));
|
||||
$DB->delete_records_select('config_plugins', "plugin = 'message' AND ".$DB->sql_like('name', '?', false), array("%_provider_{$component}_{$dbprovider->name}_%"));
|
||||
$DB->delete_records_select('user_preferences', $DB->sql_like('name', '?', false), array("message_provider_{$component}_{$dbprovider->name}_%"));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function populates default message preferences for all existing providers
|
||||
* when the new message processor is added.
|
||||
*
|
||||
* @param string $processorname The name of message processor plugin (e.g. 'email', 'jabber')
|
||||
* @return void
|
||||
* @throws invalid_parameter_exception if $processorname does not exist
|
||||
*/
|
||||
function message_update_processors($processorname) {
|
||||
global $DB;
|
||||
|
||||
// validate if our processor exists
|
||||
$processor = $DB->get_records('message_processors', array('name' => $processorname));
|
||||
if (empty($processor)) {
|
||||
throw new invalid_parameter_exception();
|
||||
}
|
||||
|
||||
$providers = $DB->get_records_sql('SELECT DISTINCT component FROM {message_providers}');
|
||||
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
foreach ($providers as $provider) {
|
||||
// load message providers from files
|
||||
$fileproviders = message_get_providers_from_file($provider->component);
|
||||
foreach ($fileproviders as $messagename => $fileprovider) {
|
||||
message_set_default_message_preference($provider->component, $messagename, $fileprovider, $processorname);
|
||||
}
|
||||
}
|
||||
$transaction->allow_commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting default messaging preference for particular message provider
|
||||
*
|
||||
* @param string $component The name of component (e.g. moodle, mod_forum, etc.)
|
||||
* @param string $messagename The name of message provider
|
||||
* @param array $fileprovider The value of $messagename key in the array defined in plugin messages.php
|
||||
* @param string $processorname The optinal name of message processor
|
||||
* @return void
|
||||
*/
|
||||
function message_set_default_message_preference($component, $messagename, $fileprovider, $processorname='') {
|
||||
global $DB;
|
||||
|
||||
// Fetch message processors
|
||||
$condition = null;
|
||||
// If we need to process a particular processor, set the select condition
|
||||
if (!empty($processorname)) {
|
||||
$condition = array('name' => $processorname);
|
||||
}
|
||||
$processors = $DB->get_records('message_processors', $condition);
|
||||
|
||||
// load default messaging preferences
|
||||
$defaultpreferences = get_message_output_default_preferences();
|
||||
|
||||
// Setting default preference
|
||||
$componentproviderbase = $component.'_'.$messagename;
|
||||
$loggedinpref = array();
|
||||
$loggedoffpref = array();
|
||||
// set 'permitted' preference first for each messaging processor
|
||||
foreach ($processors as $processor) {
|
||||
$preferencename = $processor->name.'_provider_'.$componentproviderbase.'_permitted';
|
||||
// if we do not have this setting yet, set it
|
||||
if (!isset($defaultpreferences->{$preferencename})) {
|
||||
// determine plugin default settings
|
||||
$plugindefault = 0;
|
||||
if (isset($fileprovider['defaults'][$processor->name])) {
|
||||
$plugindefault = $fileprovider['defaults'][$processor->name];
|
||||
}
|
||||
// get string values of the settings
|
||||
list($permitted, $loggedin, $loggedoff) = translate_message_default_setting($plugindefault, $processor->name);
|
||||
// store default preferences for current processor
|
||||
set_config($preferencename, $permitted, 'message');
|
||||
// save loggedin/loggedoff settings
|
||||
if ($loggedin) {
|
||||
$loggedinpref[] = $processor->name;
|
||||
}
|
||||
if ($loggedoff) {
|
||||
$loggedoffpref[] = $processor->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
// now set loggedin/loggedoff preferences
|
||||
if (!empty($loggedinpref)) {
|
||||
$preferencename = 'message_provider_'.$componentproviderbase.'_loggedin';
|
||||
if (isset($defaultpreferences->{$preferencename})) {
|
||||
// We have the default preferences for this message provider, which
|
||||
// likely means that we have been adding a new processor. Add defaults
|
||||
// to exisitng preferences.
|
||||
$loggedinpref = array_merge($loggedinpref, explode(',', $defaultpreferences->{$preferencename}));
|
||||
}
|
||||
set_config($preferencename, join(',', $loggedinpref), 'message');
|
||||
}
|
||||
if (!empty($loggedoffpref)) {
|
||||
$preferencename = 'message_provider_'.$componentproviderbase.'_loggedoff';
|
||||
if (isset($defaultpreferences->{$preferencename})) {
|
||||
// We have the default preferences for this message provider, which
|
||||
// likely means that we have been adding a new processor. Add defaults
|
||||
// to exisitng preferences.
|
||||
$loggedoffpref = array_merge($loggedoffpref, explode(',', $defaultpreferences->{$preferencename}));
|
||||
}
|
||||
set_config($preferencename, join(',', $loggedoffpref), 'message');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the active providers for the current user, based on capability
|
||||
*
|
||||
* @return array of message providers
|
||||
*/
|
||||
function message_get_my_providers() {
|
||||
@ -253,6 +378,7 @@ function message_get_my_providers() {
|
||||
|
||||
/**
|
||||
* Gets the message providers that are in the database for this component.
|
||||
*
|
||||
* @param $component - examples: 'moodle', 'mod/forum', 'block/quiz_results'
|
||||
* @return array of message providers
|
||||
*
|
||||
@ -267,6 +393,7 @@ function message_get_providers_from_db($component) {
|
||||
/**
|
||||
* Loads the messages definitions for the component (from file). If no
|
||||
* messages are defined for the component, we simply return an empty array.
|
||||
*
|
||||
* @param $component - examples: 'moodle', 'mod_forum', 'block_quiz_results'
|
||||
* @return array of message providerss or empty array if not exists
|
||||
*
|
||||
@ -285,64 +412,43 @@ function message_get_providers_from_file($component) {
|
||||
if (empty($messageprovider['capability'])) {
|
||||
$messageproviders[$name]['capability'] = NULL;
|
||||
}
|
||||
if (empty($messageprovider['defaults'])) {
|
||||
$messageproviders[$name]['defaults'] = array();
|
||||
}
|
||||
}
|
||||
|
||||
return $messageproviders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all message providers
|
||||
* @param $component - examples: 'moodle', 'mod/forum', 'block/quiz_results'
|
||||
* Remove all message providers for particular plugin and corresponding settings
|
||||
*
|
||||
* @param string $component - examples: 'moodle', 'mod_forum', 'block_quiz_results'
|
||||
* @return void
|
||||
*/
|
||||
function message_uninstall($component) {
|
||||
function message_provider_uninstall($component) {
|
||||
global $DB;
|
||||
return $DB->delete_records('message_providers', array('component' => $component));
|
||||
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
$DB->delete_records('message_providers', array('component' => $component));
|
||||
$DB->delete_records_select('config_plugins', "plugin = 'message' AND ".$DB->sql_like('name', '?', false), array("%_provider_{$component}_%"));
|
||||
$DB->delete_records_select('user_preferences', $DB->sql_like('name', '?', false), array("message_provider_{$component}_%"));
|
||||
$transaction->allow_commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default message preferences.
|
||||
* @param $user - User to set message preferences
|
||||
* Remove message processor
|
||||
*
|
||||
* @param string $name - examples: 'email', 'jabber'
|
||||
* @return void
|
||||
*/
|
||||
function message_set_default_message_preferences($user) {
|
||||
function message_processor_uninstall($name) {
|
||||
global $DB;
|
||||
|
||||
//check for the pre 2.0 disable email setting
|
||||
$useemail = empty($user->emailstop);
|
||||
|
||||
//look for the pre-2.0 preference if it exists
|
||||
$oldpreference = get_user_preferences('message_showmessagewindow', -1, $user->id);
|
||||
//if they elected to see popups or the preference didnt exist
|
||||
$usepopups = (intval($oldpreference)==1 || intval($oldpreference)==-1);
|
||||
|
||||
$defaultonlineprocessor = 'none';
|
||||
$defaultofflineprocessor = 'none';
|
||||
|
||||
if ($useemail) {
|
||||
$defaultonlineprocessor = 'email';
|
||||
$defaultofflineprocessor = 'email';
|
||||
} else if ($usepopups) {
|
||||
$defaultonlineprocessor = 'popup';
|
||||
$defaultofflineprocessor = 'popup';
|
||||
}
|
||||
|
||||
$offlineprocessortouse = $onlineprocessortouse = null;
|
||||
|
||||
$providers = $DB->get_records('message_providers');
|
||||
$preferences = array();
|
||||
|
||||
foreach ($providers as $providerid => $provider) {
|
||||
|
||||
//force some specific defaults for IMs
|
||||
if ($provider->name=='instantmessage' && $usepopups && $useemail) {
|
||||
$onlineprocessortouse = 'popup';
|
||||
$offlineprocessortouse = 'email,popup';
|
||||
} else {
|
||||
$onlineprocessortouse = $defaultonlineprocessor;
|
||||
$offlineprocessortouse = $defaultofflineprocessor;
|
||||
}
|
||||
|
||||
$preferences['message_provider_'.$provider->component.'_'.$provider->name.'_loggedin'] = $onlineprocessortouse;
|
||||
$preferences['message_provider_'.$provider->component.'_'.$provider->name.'_loggedoff'] = $offlineprocessortouse;
|
||||
}
|
||||
return set_user_preferences($preferences, $user->id);
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
$DB->delete_records('message_processors', array('name' => $name));
|
||||
// delete permission preferences only, we do not care about loggedin/loggedoff
|
||||
// defaults, they will be removed on the next attempt to update the preferences
|
||||
$DB->delete_records_select('config_plugins', "plugin = 'message' AND ".$DB->sql_like('name', '?', false), array("{$name}_provider_%"));
|
||||
$transaction->allow_commit();
|
||||
}
|
||||
|
@ -424,6 +424,10 @@ define('HUB_HUBDIRECTORYURL', "http://hubdirectory.moodle.org");
|
||||
*/
|
||||
define('HUB_MOODLEORGHUBURL', "http://hub.moodle.org");
|
||||
|
||||
/**
|
||||
* Moodle mobile app service name
|
||||
*/
|
||||
define('MOODLE_OFFICIAL_MOBILE_SERVICE', 'moodle_mobile_app');
|
||||
|
||||
/// PARAMETER HANDLING ////////////////////////////////////////////////////
|
||||
|
||||
@ -1554,26 +1558,27 @@ function get_user_preferences($name = null, $default = null, $user = null) {
|
||||
* @param int $hour The hour part to create timestamp of
|
||||
* @param int $minute The minute part to create timestamp of
|
||||
* @param int $second The second part to create timestamp of
|
||||
* @param float $timezone Timezone modifier
|
||||
* @param bool $applydst Toggle Daylight Saving Time, default true
|
||||
* @param mixed $timezone Timezone modifier, if 99 then use default user's timezone
|
||||
* @param bool $applydst Toggle Daylight Saving Time, default true, will be
|
||||
* applied only if timezone is 99 or string.
|
||||
* @return int timestamp
|
||||
*/
|
||||
function make_timestamp($year, $month=1, $day=1, $hour=0, $minute=0, $second=0, $timezone=99, $applydst=true) {
|
||||
|
||||
$strtimezone = NULL;
|
||||
if (!is_numeric($timezone)) {
|
||||
$strtimezone = $timezone;
|
||||
}
|
||||
//save input timezone, required for dst offset check.
|
||||
$passedtimezone = $timezone;
|
||||
|
||||
$timezone = get_user_timezone_offset($timezone);
|
||||
|
||||
if (abs($timezone) > 13) {
|
||||
if (abs($timezone) > 13) { //server time
|
||||
$time = mktime((int)$hour, (int)$minute, (int)$second, (int)$month, (int)$day, (int)$year);
|
||||
} else {
|
||||
$time = gmmktime((int)$hour, (int)$minute, (int)$second, (int)$month, (int)$day, (int)$year);
|
||||
$time = usertime($time, $timezone);
|
||||
if($applydst) {
|
||||
$time -= dst_offset_on($time, $strtimezone);
|
||||
|
||||
//Apply dst for string timezones or if 99 then try dst offset with user's default timezone
|
||||
if ($applydst && ((99 == $passedtimezone) || !is_numeric($passedtimezone))) {
|
||||
$time -= dst_offset_on($time, $passedtimezone);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1664,7 +1669,8 @@ function make_timestamp($year, $month=1, $day=1, $hour=0, $minute=0, $second=0,
|
||||
* @param int $date the timestamp in UTC, as obtained from the database.
|
||||
* @param string $format strftime format. You should probably get this using
|
||||
* get_string('strftime...', 'langconfig');
|
||||
* @param float $timezone by default, uses the user's time zone.
|
||||
* @param mixed $timezone by default, uses the user's time zone. if numeric and
|
||||
* not 99 then daylight saving will not be added.
|
||||
* @param bool $fixday If true (default) then the leading zero from %d is removed.
|
||||
* If false then the leading zero is maintained.
|
||||
* @return string the formatted date/time.
|
||||
@ -1673,11 +1679,6 @@ function userdate($date, $format = '', $timezone = 99, $fixday = true) {
|
||||
|
||||
global $CFG;
|
||||
|
||||
$strtimezone = NULL;
|
||||
if (!is_numeric($timezone)) {
|
||||
$strtimezone = $timezone;
|
||||
}
|
||||
|
||||
if (empty($format)) {
|
||||
$format = get_string('strftimedaydatetime', 'langconfig');
|
||||
}
|
||||
@ -1689,7 +1690,11 @@ function userdate($date, $format = '', $timezone = 99, $fixday = true) {
|
||||
$fixday = ($formatnoday != $format);
|
||||
}
|
||||
|
||||
$date += dst_offset_on($date, $strtimezone);
|
||||
//add daylight saving offset for string timezones only, as we can't get dst for
|
||||
//float values. if timezone is 99 (user default timezone), then try update dst.
|
||||
if ((99 == $timezone) || !is_numeric($timezone)) {
|
||||
$date += dst_offset_on($date, $timezone);
|
||||
}
|
||||
|
||||
$timezone = get_user_timezone_offset($timezone);
|
||||
|
||||
@ -1732,15 +1737,14 @@ function userdate($date, $format = '', $timezone = 99, $fixday = true) {
|
||||
* @todo Finish documenting this function
|
||||
* @uses HOURSECS
|
||||
* @param int $time Timestamp in GMT
|
||||
* @param float $timezone ?
|
||||
* @param mixed $timezone offset time with timezone, if float and not 99, then no
|
||||
* dst offset is applyed
|
||||
* @return array An array that represents the date in user time
|
||||
*/
|
||||
function usergetdate($time, $timezone=99) {
|
||||
|
||||
$strtimezone = NULL;
|
||||
if (!is_numeric($timezone)) {
|
||||
$strtimezone = $timezone;
|
||||
}
|
||||
//save input timezone, required for dst offset check.
|
||||
$passedtimezone = $timezone;
|
||||
|
||||
$timezone = get_user_timezone_offset($timezone);
|
||||
|
||||
@ -1748,8 +1752,12 @@ function usergetdate($time, $timezone=99) {
|
||||
return getdate($time);
|
||||
}
|
||||
|
||||
// There is no gmgetdate so we use gmdate instead
|
||||
$time += dst_offset_on($time, $strtimezone);
|
||||
//add daylight saving offset for string timezones only, as we can't get dst for
|
||||
//float values. if timezone is 99 (user default timezone), then try update dst.
|
||||
if ($passedtimezone == 99 || !is_numeric($passedtimezone)) {
|
||||
$time += dst_offset_on($time, $passedtimezone);
|
||||
}
|
||||
|
||||
$time += intval((float)$timezone * HOURSECS);
|
||||
|
||||
$datestring = gmstrftime('%B_%A_%j_%Y_%m_%w_%d_%H_%M_%S', $time);
|
||||
@ -1900,7 +1908,7 @@ function get_timezone_offset($tz) {
|
||||
*
|
||||
* @global object
|
||||
* @global object
|
||||
* @param float $tz If this value is provided and not equal to 99, it will be returned as is and no other settings will be checked
|
||||
* @param mixed $tz If this value is provided and not equal to 99, it will be returned as is and no other settings will be checked
|
||||
* @return mixed
|
||||
*/
|
||||
function get_user_timezone($tz = 99) {
|
||||
@ -1954,7 +1962,7 @@ function get_timezone_record($timezonename) {
|
||||
* @global object
|
||||
* @param mixed $from_year Start year for the table, defaults to 1971
|
||||
* @param mixed $to_year End year for the table, defaults to 2035
|
||||
* @param mixed $strtimezone
|
||||
* @param mixed $strtimezone, if null or 99 then user's default timezone is used
|
||||
* @return bool
|
||||
*/
|
||||
function calculate_user_dst_table($from_year = NULL, $to_year = NULL, $strtimezone = NULL) {
|
||||
@ -2115,9 +2123,12 @@ function dst_changes_for_year($year, $timezone) {
|
||||
|
||||
/**
|
||||
* Calculates the Daylight Saving Offset for a given date/time (timestamp)
|
||||
* - Note: Daylight saving only works for string timezones and not for float.
|
||||
*
|
||||
* @global object
|
||||
* @param int $time must NOT be compensated at all, it has to be a pure timestamp
|
||||
* @param mixed $strtimezone timezone for which offset is expected, if 99 or null
|
||||
* then user's default timezone is used.
|
||||
* @return int
|
||||
*/
|
||||
function dst_offset_on($time, $strtimezone = NULL) {
|
||||
@ -7067,7 +7078,8 @@ function get_plugin_types($fullpaths=true) {
|
||||
static $fullinfo = null;
|
||||
|
||||
if (!$info) {
|
||||
$info = array('mod' => 'mod',
|
||||
$info = array('qtype' => 'question/type',
|
||||
'mod' => 'mod',
|
||||
'auth' => 'auth',
|
||||
'enrol' => 'enrol',
|
||||
'message' => 'message/output',
|
||||
@ -7085,7 +7097,7 @@ function get_plugin_types($fullpaths=true) {
|
||||
'webservice' => 'webservice',
|
||||
'repository' => 'repository',
|
||||
'portfolio' => 'portfolio',
|
||||
'qtype' => 'question/type',
|
||||
'qbehaviour' => 'question/behaviour',
|
||||
'qformat' => 'question/format',
|
||||
'plagiarism' => 'plagiarism',
|
||||
'theme' => 'theme'); // this is a bit hacky, themes may be in $CFG->themedir too
|
||||
@ -7603,6 +7615,143 @@ function check_php_version($version='5.2.4') {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a device/browser combination is mobile, tablet, legacy, default or the result of
|
||||
* an optional admin specified regular expression. If enabledevicedetection is set to no or not set
|
||||
* it returns default
|
||||
*
|
||||
* @return string device type
|
||||
*/
|
||||
function get_device_type() {
|
||||
global $CFG;
|
||||
|
||||
if (empty($CFG->enabledevicedetection) || empty($_SERVER['HTTP_USER_AGENT'])) {
|
||||
return 'default';
|
||||
}
|
||||
|
||||
$useragent = $_SERVER['HTTP_USER_AGENT'];
|
||||
|
||||
if (!empty($CFG->devicedetectregex)) {
|
||||
$regexes = json_decode($CFG->devicedetectregex);
|
||||
|
||||
foreach ($regexes as $value=>$regex) {
|
||||
if (preg_match($regex, $useragent)) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//mobile detection PHP direct copy from open source detectmobilebrowser.com
|
||||
$phonesregex = '/android|avantgo|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i';
|
||||
$modelsregex = '/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i';
|
||||
if (preg_match($phonesregex,$useragent) || preg_match($modelsregex,substr($useragent, 0, 4))){
|
||||
return 'mobile';
|
||||
}
|
||||
|
||||
$tabletregex = '/Tablet browser|iPad|iProd|GT-P1000|GT-I9000|SHW-M180S|SGH-T849|SCH-I800|Build\/ERE27|sholest/i';
|
||||
if (preg_match($tabletregex, $useragent)) {
|
||||
return 'tablet';
|
||||
}
|
||||
|
||||
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 6.') !== false) {
|
||||
return 'legacy';
|
||||
}
|
||||
|
||||
return 'default';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the device types supporting by Moodle
|
||||
*
|
||||
* @param boolean $incusertypes includes types specified using the devicedetectregex admin setting
|
||||
* @return array $types
|
||||
*/
|
||||
function get_device_type_list($incusertypes = true) {
|
||||
global $CFG;
|
||||
|
||||
$types = array('default', 'legacy', 'mobile', 'tablet');
|
||||
|
||||
if ($incusertypes && !empty($CFG->devicedetectregex)) {
|
||||
$regexes = json_decode($CFG->devicedetectregex);
|
||||
|
||||
foreach ($regexes as $value => $regex) {
|
||||
$types[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the theme selected for a particular device or false if none selected.
|
||||
*
|
||||
* @param string $devicetype
|
||||
* @return string|false The name of the theme to use for the device or the false if not set
|
||||
*/
|
||||
function get_selected_theme_for_device_type($devicetype = null) {
|
||||
global $CFG;
|
||||
|
||||
if (empty($devicetype)) {
|
||||
$devicetype = get_user_device_type();
|
||||
}
|
||||
|
||||
$themevarname = get_device_cfg_var_name($devicetype);
|
||||
if (empty($CFG->$themevarname)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $CFG->$themevarname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the device type theme var in $CFG (because there is not a standard convention to allow backwards compatability
|
||||
*
|
||||
* @param string $devicetype
|
||||
* @return string The config variable to use to determine the theme
|
||||
*/
|
||||
function get_device_cfg_var_name($devicetype = null) {
|
||||
if ($devicetype == 'default' || empty($devicetype)) {
|
||||
return 'theme';
|
||||
}
|
||||
|
||||
return 'theme' . $devicetype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the user to switch the device they are seeing the theme for.
|
||||
* This allows mobile users to switch back to the default theme, or theme for any other device.
|
||||
*
|
||||
* @param string $newdevice The device the user is currently using.
|
||||
* @return string The device the user has switched to
|
||||
*/
|
||||
function set_user_device_type($newdevice) {
|
||||
global $USER;
|
||||
|
||||
$devicetype = get_device_type();
|
||||
$devicetypes = get_device_type_list();
|
||||
|
||||
if ($newdevice == $devicetype) {
|
||||
unset_user_preference('switchdevice'.$devicetype);
|
||||
} else if (in_array($newdevice, $devicetypes)) {
|
||||
set_user_preference('switchdevice'.$devicetype, $newdevice);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device the user is currently using, or if the user has chosen to switch devices
|
||||
* for the current device type the type they have switched to.
|
||||
*
|
||||
* @return string The device the user is currently using or wishes to use
|
||||
*/
|
||||
function get_user_device_type() {
|
||||
$device = get_device_type();
|
||||
$switched = get_user_preferences('switchdevice'.$device, false);
|
||||
if ($switched != false) {
|
||||
return $switched;
|
||||
}
|
||||
return $device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one or several CSS class names that match the user's browser. These can be put
|
||||
* in the body tag of the page to apply browser-specific rules without relying on CSS hacks
|
||||
|
@ -362,10 +362,14 @@ class core_renderer extends renderer_base {
|
||||
// but some of the content won't be known until later, so we return a placeholder
|
||||
// for now. This will be replaced with the real content in {@link footer()}.
|
||||
$output = self::PERFORMANCE_INFO_TOKEN;
|
||||
if ($this->page->legacythemeinuse) {
|
||||
if ($this->page->devicetypeinuse == 'legacy') {
|
||||
// The legacy theme is in use print the notification
|
||||
$output .= html_writer::tag('div', get_string('legacythemeinuse'), array('class'=>'legacythemeinuse'));
|
||||
}
|
||||
|
||||
// Get links to switch device types (only shown for users not on a default device)
|
||||
$output .= $this->theme_switch_links();
|
||||
|
||||
if (!empty($CFG->debugpageinfo)) {
|
||||
$output .= '<div class="performanceinfo pageinfo">This page is: ' . $this->page->debug_summary() . '</div>';
|
||||
}
|
||||
@ -2496,8 +2500,40 @@ EOD;
|
||||
// Return the sub menu
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders theme links for switching between default and other themes.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function theme_switch_links() {
|
||||
|
||||
$actualdevice = get_device_type();
|
||||
$currentdevice = $this->page->devicetypeinuse;
|
||||
$switched = ($actualdevice != $currentdevice);
|
||||
|
||||
if (!$switched && $currentdevice == 'default' && $actualdevice == 'default') {
|
||||
// The user is using the a default device and hasn't switched so don't shown the switch
|
||||
// device links.
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($switched) {
|
||||
$linktext = get_string('switchdevicerecommended');
|
||||
$devicetype = $actualdevice;
|
||||
} else {
|
||||
$linktext = get_string('switchdevicedefault');
|
||||
$devicetype = 'default';
|
||||
}
|
||||
$linkurl = new moodle_url('/theme/switchdevice.php', array('url' => $this->page->url, 'device' => $devicetype, 'sesskey' => sesskey()));
|
||||
|
||||
$content = html_writer::start_tag('div', array('id' => 'theme_switch_link'));
|
||||
$content .= html_writer::link($linkurl, $linktext);
|
||||
$content .= html_writer::end_tag('div');
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
/// RENDERERS
|
||||
|
||||
|
@ -445,6 +445,7 @@ class page_requirements_manager {
|
||||
break;
|
||||
case 'core_message':
|
||||
$module = array('name' => 'core_message',
|
||||
'requires' => array('base', 'node', 'event', 'node-event-simulate'),
|
||||
'fullpath' => '/message/module.js');
|
||||
break;
|
||||
case 'core_flashdetect':
|
||||
|
@ -64,13 +64,13 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @property-read object $course The current course that we are inside - a row from the
|
||||
* course table. (Also available as $COURSE global.) If we are not inside
|
||||
* an actual course, this will be the site course.
|
||||
* @property-read string $devicetypeinuse The name of the device type in use
|
||||
* @property-read string $docspath The path to the Moodle docs for this page.
|
||||
* @property-read string $focuscontrol The id of the HTML element to be focused when the page has loaded.
|
||||
* @property-read bool $headerprinted
|
||||
* @property-read string $heading The main heading that should be displayed at the top of the <body>.
|
||||
* @property-read string $headingmenu The menu (or actions) to display in the heading
|
||||
* @property-read array $layout_options Returns arrays with options for layout file.
|
||||
* @property-read bool $legacythemeinuse Returns true if the legacy theme is being used.
|
||||
* @property-read navbar $navbar Returns the navbar object used to display the navbar
|
||||
* @property-read global_navigation $navigation Returns the global navigation structure
|
||||
* @property-read xml_container_stack $opencontainers Tracks XHTML tags on this page that have been opened but not closed.
|
||||
@ -217,10 +217,12 @@ class moodle_page {
|
||||
protected $_legacybrowsers = array('MSIE' => 6.0);
|
||||
|
||||
/**
|
||||
* Is set to true if the chosen legacy theme is in use. False by default.
|
||||
* @var bool
|
||||
* Is set to the name of the device type in use.
|
||||
* This will we worked out when it is first used.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_legacythemeinuse = false;
|
||||
protected $_devicetypeinuse = null;
|
||||
|
||||
protected $_https_login_required = false;
|
||||
|
||||
@ -522,12 +524,26 @@ class moodle_page {
|
||||
return $this->_theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Please do not call this method directly, use the ->devicetypeinuse syntax. {@link __get()}.
|
||||
*
|
||||
* @return string The device type being used.
|
||||
*/
|
||||
protected function magic_get_devicetypeinuse() {
|
||||
if (empty($this->_devicetypeinuse)) {
|
||||
$this->_devicetypeinuse = get_user_device_type();
|
||||
}
|
||||
return $this->_devicetypeinuse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Please do not call this method directly, use the ->legacythemeinuse syntax. {@link __get()}.
|
||||
* @deprecated since 2.1
|
||||
* @return bool
|
||||
*/
|
||||
protected function magic_get_legacythemeinuse() {
|
||||
return ($this->_legacythemeinuse);
|
||||
debugging('$PAGE->legacythemeinuse is a deprecated property - please use $PAGE->devicetypeinuse and check if it is equal to legacy.', DEVELOPER_DEBUG);
|
||||
return ($this->devicetypeinuse == 'legacy');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1280,16 +1296,15 @@ class moodle_page {
|
||||
}
|
||||
}
|
||||
|
||||
$theme = '';
|
||||
foreach ($themeorder as $themetype) {
|
||||
switch ($themetype) {
|
||||
case 'course':
|
||||
if (!empty($CFG->allowcoursethemes) and !empty($this->course->theme)) {
|
||||
return $this->course->theme;
|
||||
if (!empty($CFG->allowcoursethemes) && !empty($this->_course->theme) && $this->devicetypeinuse == 'default') {
|
||||
return $this->_course->theme;
|
||||
}
|
||||
|
||||
case 'category':
|
||||
if (!empty($CFG->allowcategorythemes)) {
|
||||
if (!empty($CFG->allowcategorythemes) && $this->devicetypeinuse == 'default') {
|
||||
$categories = $this->categories;
|
||||
foreach ($categories as $category) {
|
||||
if (!empty($category->theme)) {
|
||||
@ -1304,7 +1319,7 @@ class moodle_page {
|
||||
}
|
||||
|
||||
case 'user':
|
||||
if (!empty($CFG->allowuserthemes) and !empty($USER->theme)) {
|
||||
if (!empty($CFG->allowuserthemes) && !empty($USER->theme) && $this->devicetypeinuse == 'default') {
|
||||
if ($mnetpeertheme) {
|
||||
return $mnetpeertheme;
|
||||
} else {
|
||||
@ -1315,33 +1330,23 @@ class moodle_page {
|
||||
case 'site':
|
||||
if ($mnetpeertheme) {
|
||||
return $mnetpeertheme;
|
||||
} else if(!empty($CFG->themelegacy) && $this->browser_is_outdated()) {
|
||||
$this->_legacythemeinuse = true;
|
||||
return $CFG->themelegacy;
|
||||
} else {
|
||||
return $CFG->theme;
|
||||
}
|
||||
// First try for the device the user is using.
|
||||
$devicetheme = get_selected_theme_for_device_type($this->devicetypeinuse);
|
||||
if (!empty($devicetheme)) {
|
||||
return $devicetheme;
|
||||
}
|
||||
// Next try for the default device (as a fallback)
|
||||
$devicetheme = get_selected_theme_for_device_type('default');
|
||||
if (!empty($devicetheme)) {
|
||||
return $devicetheme;
|
||||
}
|
||||
// The default device theme isn't set up - use the overall default theme.
|
||||
return theme_config::DEFAULT_THEME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the current browser should
|
||||
* default to the admin-selected legacy theme
|
||||
*
|
||||
* @return true if legacy theme should be used, otherwise false
|
||||
*
|
||||
*/
|
||||
protected function browser_is_outdated() {
|
||||
foreach($this->_legacybrowsers as $browser => $version) {
|
||||
// Check the browser is valid first then that its version is suitable
|
||||
if(check_browser_version($browser, '0') &&
|
||||
!check_browser_version($browser, $version)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets ->pagetype from the script name. For example, if the script that was
|
||||
@ -1448,8 +1453,8 @@ class moodle_page {
|
||||
$this->add_body_class('drag');
|
||||
}
|
||||
|
||||
if ($this->_legacythemeinuse) {
|
||||
$this->add_body_class('legacytheme');
|
||||
if ($this->_devicetypeinuse != 'default') {
|
||||
$this->add_body_class($this->_devicetypeinuse . 'theme');
|
||||
}
|
||||
}
|
||||
|
||||
|
2855
lib/questionlib.php
2855
lib/questionlib.php
File diff suppressed because it is too large
Load Diff
@ -487,10 +487,15 @@ function resourcelib_embed_general($fullurl, $title, $clicktoopen, $mimetype) {
|
||||
}
|
||||
|
||||
$iframe = false;
|
||||
|
||||
$param = '<param name="src" value="'.$fullurl.'" />';
|
||||
|
||||
// IE can not embed stuff properly if stored on different server
|
||||
// that is why we use iframe instead, unfortunately this tag does not validate
|
||||
// in xhtml strict mode
|
||||
if ($mimetype === 'text/html' and check_browser_version('MSIE', 5)) {
|
||||
// The param tag needs to be removed to avoid trouble in IE.
|
||||
$param = '';
|
||||
if (preg_match('(^https?://[^/]*)', $fullurl, $matches)) {
|
||||
if (strpos($CFG->wwwroot, $matches[0]) !== 0) {
|
||||
$iframe = true;
|
||||
@ -510,7 +515,7 @@ EOT;
|
||||
$code = <<<EOT
|
||||
<div class="resourcecontent resourcegeneral">
|
||||
<object id="resourceobject" data="$fullurl" type="$mimetype" width="800" height="600">
|
||||
<param name="src" value="$fullurl" />
|
||||
$param
|
||||
$clicktoopen
|
||||
</object>
|
||||
</div>
|
||||
|
@ -515,7 +515,14 @@ class moodlelib_test extends UnitTestCase {
|
||||
}
|
||||
|
||||
function test_usergetdate() {
|
||||
global $USER;
|
||||
global $USER, $CFG;
|
||||
|
||||
//Check if forcetimezone is set then save it and set it to use user timezone
|
||||
$cfgforcetimezone = null;
|
||||
if (isset($CFG->forcetimezone)) {
|
||||
$cfgforcetimezone = $CFG->forcetimezone;
|
||||
$CFG->forcetimezone = 99; //get user default timezone.
|
||||
}
|
||||
|
||||
$userstimezone = $USER->timezone;
|
||||
$USER->timezone = 2;//set the timezone to a known state
|
||||
@ -559,6 +566,12 @@ class moodlelib_test extends UnitTestCase {
|
||||
|
||||
//set the timezone back to what it was
|
||||
$USER->timezone = $userstimezone;
|
||||
|
||||
//restore forcetimezone if changed.
|
||||
if (!is_null($cfgforcetimezone)) {
|
||||
$CFG->forcetimezone = $cfgforcetimezone;
|
||||
}
|
||||
|
||||
setlocale(LC_TIME, $oldlocale);
|
||||
}
|
||||
|
||||
@ -757,4 +770,286 @@ class moodlelib_test extends UnitTestCase {
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public function test_userdate() {
|
||||
global $USER, $CFG;
|
||||
|
||||
$testvalues = array(
|
||||
array(
|
||||
'time' => '1309514400',
|
||||
'usertimezone' => 'America/Moncton',
|
||||
'timezone' => '0.0', //no dst offset
|
||||
'expectedoutput' => 'Friday, 1 July 2011, 10:00 AM'
|
||||
),
|
||||
array(
|
||||
'time' => '1309514400',
|
||||
'usertimezone' => 'America/Moncton',
|
||||
'timezone' => '99', //dst offset and timezone offset.
|
||||
'expectedoutput' => 'Friday, 1 July 2011, 07:00 AM'
|
||||
),
|
||||
array(
|
||||
'time' => '1309514400',
|
||||
'usertimezone' => 'America/Moncton',
|
||||
'timezone' => 'America/Moncton', //dst offset and timezone offset.
|
||||
'expectedoutput' => 'Friday, 1 July 2011, 07:00 AM'
|
||||
),
|
||||
array(
|
||||
'time' => '1293876000 ',
|
||||
'usertimezone' => 'America/Moncton',
|
||||
'timezone' => '0.0', //no dst offset
|
||||
'expectedoutput' => 'Saturday, 1 January 2011, 10:00 AM'
|
||||
),
|
||||
array(
|
||||
'time' => '1293876000 ',
|
||||
'usertimezone' => 'America/Moncton',
|
||||
'timezone' => '99', //no dst offset in jan, so just timezone offset.
|
||||
'expectedoutput' => 'Saturday, 1 January 2011, 06:00 AM'
|
||||
),
|
||||
array(
|
||||
'time' => '1293876000 ',
|
||||
'usertimezone' => 'America/Moncton',
|
||||
'timezone' => 'America/Moncton', //no dst offset in jan
|
||||
'expectedoutput' => 'Saturday, 1 January 2011, 06:00 AM'
|
||||
),
|
||||
array(
|
||||
'time' => '1293876000 ',
|
||||
'usertimezone' => '2',
|
||||
'timezone' => '99', //take user timezone
|
||||
'expectedoutput' => 'Saturday, 1 January 2011, 12:00 PM'
|
||||
),
|
||||
array(
|
||||
'time' => '1293876000 ',
|
||||
'usertimezone' => '-2',
|
||||
'timezone' => '99', //take user timezone
|
||||
'expectedoutput' => 'Saturday, 1 January 2011, 08:00 AM'
|
||||
),
|
||||
array(
|
||||
'time' => '1293876000 ',
|
||||
'usertimezone' => '-10',
|
||||
'timezone' => '2', //take this timezone
|
||||
'expectedoutput' => 'Saturday, 1 January 2011, 12:00 PM'
|
||||
),
|
||||
array(
|
||||
'time' => '1293876000 ',
|
||||
'usertimezone' => '-10',
|
||||
'timezone' => '-2', //take this timezone
|
||||
'expectedoutput' => 'Saturday, 1 January 2011, 08:00 AM'
|
||||
),
|
||||
array(
|
||||
'time' => '1293876000 ',
|
||||
'usertimezone' => '-10',
|
||||
'timezone' => 'random/time', //this should show server time
|
||||
'expectedoutput' => 'Saturday, 1 January 2011, 06:00 PM'
|
||||
),
|
||||
array(
|
||||
'time' => '1293876000 ',
|
||||
'usertimezone' => '14', //server time zone
|
||||
'timezone' => '99', //this should show user time
|
||||
'expectedoutput' => 'Saturday, 1 January 2011, 06:00 PM'
|
||||
),
|
||||
);
|
||||
|
||||
//Check if forcetimezone is set then save it and set it to use user timezone
|
||||
$cfgforcetimezone = null;
|
||||
if (isset($CFG->forcetimezone)) {
|
||||
$cfgforcetimezone = $CFG->forcetimezone;
|
||||
$CFG->forcetimezone = 99; //get user default timezone.
|
||||
}
|
||||
//store user default timezone to restore later
|
||||
$userstimezone = $USER->timezone;
|
||||
|
||||
// The string version of date comes from server locale setting and does
|
||||
// not respect user language, so it is necessary to reset that.
|
||||
$oldlocale = setlocale(LC_TIME, '0');
|
||||
setlocale(LC_TIME, 'en_AU.UTF-8');
|
||||
|
||||
foreach ($testvalues as $vals) {
|
||||
$USER->timezone = $vals['usertimezone'];
|
||||
$actualoutput = userdate($vals['time'], '%A, %d %B %Y, %I:%M %p', $vals['timezone']);
|
||||
$this->assertEqual($vals['expectedoutput'], $actualoutput,
|
||||
"Expected: {$vals['expectedoutput']} => Actual: {$actualoutput},
|
||||
Please check if timezones are updated (Site adminstration -> location -> update timezone)");
|
||||
}
|
||||
|
||||
//restore user timezone back to what it was
|
||||
$USER->timezone = $userstimezone;
|
||||
|
||||
//restore forcetimezone
|
||||
if (!is_null($cfgforcetimezone)) {
|
||||
$CFG->forcetimezone = $cfgforcetimezone;
|
||||
}
|
||||
|
||||
setlocale(LC_TIME, $oldlocale);
|
||||
}
|
||||
|
||||
public function test_make_timestamp() {
|
||||
global $USER, $CFG;
|
||||
|
||||
$testvalues = array(
|
||||
array(
|
||||
'usertimezone' => 'America/Moncton',
|
||||
'year' => '2011',
|
||||
'month' => '7',
|
||||
'day' => '1',
|
||||
'hour' => '10',
|
||||
'minutes' => '00',
|
||||
'seconds' => '00',
|
||||
'timezone' => '0.0', //no dst offset
|
||||
'applydst' => false,
|
||||
'expectedoutput' => '1309528800'
|
||||
),
|
||||
array(
|
||||
'usertimezone' => 'America/Moncton',
|
||||
'year' => '2011',
|
||||
'month' => '7',
|
||||
'day' => '1',
|
||||
'hour' => '10',
|
||||
'minutes' => '00',
|
||||
'seconds' => '00',
|
||||
'timezone' => '99', //user default timezone
|
||||
'applydst' => false, //don't apply dst
|
||||
'expectedoutput' => '1309528800'
|
||||
),
|
||||
array(
|
||||
'usertimezone' => 'America/Moncton',
|
||||
'year' => '2011',
|
||||
'month' => '7',
|
||||
'day' => '1',
|
||||
'hour' => '10',
|
||||
'minutes' => '00',
|
||||
'seconds' => '00',
|
||||
'timezone' => '99', //user default timezone
|
||||
'applydst' => true, //apply dst
|
||||
'expectedoutput' => '1309525200'
|
||||
),
|
||||
array(
|
||||
'usertimezone' => 'America/Moncton',
|
||||
'year' => '2011',
|
||||
'month' => '7',
|
||||
'day' => '1',
|
||||
'hour' => '10',
|
||||
'minutes' => '00',
|
||||
'seconds' => '00',
|
||||
'timezone' => 'America/Moncton', //string timezone
|
||||
'applydst' => true, //apply dst
|
||||
'expectedoutput' => '1309525200'
|
||||
),
|
||||
array(
|
||||
'usertimezone' => '2',//no dst applyed
|
||||
'year' => '2011',
|
||||
'month' => '7',
|
||||
'day' => '1',
|
||||
'hour' => '10',
|
||||
'minutes' => '00',
|
||||
'seconds' => '00',
|
||||
'timezone' => '99', //take user timezone
|
||||
'applydst' => true, //apply dst
|
||||
'expectedoutput' => '1309507200'
|
||||
),
|
||||
array(
|
||||
'usertimezone' => '-2',//no dst applyed
|
||||
'year' => '2011',
|
||||
'month' => '7',
|
||||
'day' => '1',
|
||||
'hour' => '10',
|
||||
'minutes' => '00',
|
||||
'seconds' => '00',
|
||||
'timezone' => '99', //take usertimezone
|
||||
'applydst' => true, //apply dst
|
||||
'expectedoutput' => '1309521600'
|
||||
),
|
||||
array(
|
||||
'usertimezone' => '-10',//no dst applyed
|
||||
'year' => '2011',
|
||||
'month' => '7',
|
||||
'day' => '1',
|
||||
'hour' => '10',
|
||||
'minutes' => '00',
|
||||
'seconds' => '00',
|
||||
'timezone' => '2', //take this timezone
|
||||
'applydst' => true, //apply dst
|
||||
'expectedoutput' => '1309507200'
|
||||
),
|
||||
array(
|
||||
'usertimezone' => '-10',//no dst applyed
|
||||
'year' => '2011',
|
||||
'month' => '7',
|
||||
'day' => '1',
|
||||
'hour' => '10',
|
||||
'minutes' => '00',
|
||||
'seconds' => '00',
|
||||
'timezone' => '-2', //take this timezone
|
||||
'applydst' => true, //apply dst,
|
||||
'expectedoutput' => '1309521600'
|
||||
),
|
||||
array(
|
||||
'usertimezone' => '-10',//no dst applyed
|
||||
'year' => '2011',
|
||||
'month' => '7',
|
||||
'day' => '1',
|
||||
'hour' => '10',
|
||||
'minutes' => '00',
|
||||
'seconds' => '00',
|
||||
'timezone' => 'random/time', //This should show server time
|
||||
'applydst' => true, //apply dst,
|
||||
'expectedoutput' => '1309485600'
|
||||
),
|
||||
array(
|
||||
'usertimezone' => '14',//server time
|
||||
'year' => '2011',
|
||||
'month' => '7',
|
||||
'day' => '1',
|
||||
'hour' => '10',
|
||||
'minutes' => '00',
|
||||
'seconds' => '00',
|
||||
'timezone' => '99', //get user time
|
||||
'applydst' => true, //apply dst,
|
||||
'expectedoutput' => '1309485600'
|
||||
)
|
||||
);
|
||||
|
||||
//Check if forcetimezone is set then save it and set it to use user timezone
|
||||
$cfgforcetimezone = null;
|
||||
if (isset($CFG->forcetimezone)) {
|
||||
$cfgforcetimezone = $CFG->forcetimezone;
|
||||
$CFG->forcetimezone = 99; //get user default timezone.
|
||||
}
|
||||
|
||||
//store user default timezone to restore later
|
||||
$userstimezone = $USER->timezone;
|
||||
|
||||
// The string version of date comes from server locale setting and does
|
||||
// not respect user language, so it is necessary to reset that.
|
||||
$oldlocale = setlocale(LC_TIME, '0');
|
||||
setlocale(LC_TIME, 'en_AU.UTF-8');
|
||||
|
||||
//Test make_timestamp with all testvals and assert if anything wrong.
|
||||
foreach ($testvalues as $vals) {
|
||||
$USER->timezone = $vals['usertimezone'];
|
||||
$actualoutput = make_timestamp(
|
||||
$vals['year'],
|
||||
$vals['month'],
|
||||
$vals['day'],
|
||||
$vals['hour'],
|
||||
$vals['minutes'],
|
||||
$vals['seconds'],
|
||||
$vals['timezone'],
|
||||
$vals['applydst']
|
||||
);
|
||||
|
||||
$this->assertEqual($vals['expectedoutput'], $actualoutput,
|
||||
"Expected: {$vals['expectedoutput']} => Actual: {$actualoutput},
|
||||
Please check if timezones are updated (Site adminstration -> location -> update timezone)");
|
||||
}
|
||||
|
||||
//restore user timezone back to what it was
|
||||
$USER->timezone = $userstimezone;
|
||||
|
||||
//restore forcetimezone
|
||||
if (!is_null($cfgforcetimezone)) {
|
||||
$CFG->forcetimezone = $cfgforcetimezone;
|
||||
}
|
||||
|
||||
setlocale(LC_TIME, $oldlocale);
|
||||
}
|
||||
}
|
||||
|
@ -1,140 +1,60 @@
|
||||
<?php
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// NOTICE OF COPYRIGHT //
|
||||
// //
|
||||
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
|
||||
// http://moodle.org //
|
||||
// //
|
||||
// Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details: //
|
||||
// //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for (some of) ../questionlib.php.
|
||||
*
|
||||
* @copyright © 2006 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @package question
|
||||
* @package moodlecore
|
||||
* @subpackage questionbank
|
||||
* @copyright 2006 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
if (!defined('MOODLE_INTERNAL')) {
|
||||
die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
|
||||
}
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
|
||||
|
||||
/**
|
||||
* Unit tests for (some of) ../questionlib.php.
|
||||
*
|
||||
* @copyright 2006 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class questionlib_test extends UnitTestCase {
|
||||
|
||||
public static $includecoverage = array('lib/questionlib.php');
|
||||
|
||||
function test_question_sort_qtype_array() {
|
||||
$config = new stdClass();
|
||||
$config->multichoice_sortorder = '1';
|
||||
$config->calculated_sortorder = '2';
|
||||
$qtypes = array(
|
||||
'frog' => 'toad',
|
||||
'calculated' => 'newt',
|
||||
'multichoice' => 'eft',
|
||||
);
|
||||
$this->assertEqual(question_sort_qtype_array($qtypes), array(
|
||||
'multichoice' => 'eft',
|
||||
'calculated' => 'newt',
|
||||
'frog' => 'toad',
|
||||
));
|
||||
}
|
||||
|
||||
function test_question_reorder_qtypes() {
|
||||
$this->assertEqual(question_reorder_qtypes(array('t1' => '', 't2' => '', 't3' => ''), 't1', +1),
|
||||
public function test_question_reorder_qtypes() {
|
||||
$this->assertEqual(question_reorder_qtypes(
|
||||
array('t1' => '', 't2' => '', 't3' => ''), 't1', +1),
|
||||
array(0 => 't2', 1 => 't1', 2 => 't3'));
|
||||
$this->assertEqual(question_reorder_qtypes(array('t1' => '', 't2' => '', 't3' => ''), 't1', -1),
|
||||
$this->assertEqual(question_reorder_qtypes(
|
||||
array('t1' => '', 't2' => '', 't3' => ''), 't1', -1),
|
||||
array(0 => 't1', 1 => 't2', 2 => 't3'));
|
||||
$this->assertEqual(question_reorder_qtypes(array('t1' => '', 't2' => '', 't3' => ''), 't2', -1),
|
||||
$this->assertEqual(question_reorder_qtypes(
|
||||
array('t1' => '', 't2' => '', 't3' => ''), 't2', -1),
|
||||
array(0 => 't2', 1 => 't1', 2 => 't3'));
|
||||
$this->assertEqual(question_reorder_qtypes(array('t1' => '', 't2' => '', 't3' => ''), 't3', +1),
|
||||
$this->assertEqual(question_reorder_qtypes(
|
||||
array('t1' => '', 't2' => '', 't3' => ''), 't3', +1),
|
||||
array(0 => 't1', 1 => 't2', 2 => 't3'));
|
||||
$this->assertEqual(question_reorder_qtypes(array('t1' => '', 't2' => '', 't3' => ''), 'missing', +1),
|
||||
$this->assertEqual(question_reorder_qtypes(
|
||||
array('t1' => '', 't2' => '', 't3' => ''), 'missing', +1),
|
||||
array(0 => 't1', 1 => 't2', 2 => 't3'));
|
||||
}
|
||||
|
||||
function test_question_state_is_closed() {
|
||||
$state = new stdClass();
|
||||
$state->event = QUESTION_EVENTOPEN;
|
||||
$this->assertFalse(question_state_is_closed($state));
|
||||
|
||||
$state->event = QUESTION_EVENTNAVIGATE;
|
||||
$this->assertFalse(question_state_is_closed($state));
|
||||
|
||||
$state->event = QUESTION_EVENTSAVE;
|
||||
$this->assertFalse(question_state_is_closed($state));
|
||||
|
||||
$state->event = QUESTION_EVENTGRADE;
|
||||
$this->assertFalse(question_state_is_closed($state));
|
||||
|
||||
$state->event = QUESTION_EVENTDUPLICATE;
|
||||
$this->assertFalse(question_state_is_closed($state));
|
||||
|
||||
$state->event = QUESTION_EVENTVALIDATE;
|
||||
$this->assertFalse(question_state_is_closed($state));
|
||||
|
||||
$state->event = QUESTION_EVENTSUBMIT;
|
||||
$this->assertFalse(question_state_is_closed($state));
|
||||
|
||||
$state->event = QUESTION_EVENTCLOSEANDGRADE;
|
||||
$this->assertTrue(question_state_is_closed($state));
|
||||
|
||||
$state->event = QUESTION_EVENTCLOSE;
|
||||
$this->assertTrue(question_state_is_closed($state));
|
||||
|
||||
$state->event = QUESTION_EVENTMANUALGRADE;
|
||||
$this->assertTrue(question_state_is_closed($state));
|
||||
|
||||
}
|
||||
function test_question_state_is_graded() {
|
||||
$state = new stdClass();
|
||||
$state->event = QUESTION_EVENTOPEN;
|
||||
$this->assertFalse(question_state_is_graded($state));
|
||||
|
||||
$state->event = QUESTION_EVENTNAVIGATE;
|
||||
$this->assertFalse(question_state_is_graded($state));
|
||||
|
||||
$state->event = QUESTION_EVENTSAVE;
|
||||
$this->assertFalse(question_state_is_graded($state));
|
||||
|
||||
$state->event = QUESTION_EVENTDUPLICATE;
|
||||
$this->assertFalse(question_state_is_graded($state));
|
||||
|
||||
$state->event = QUESTION_EVENTVALIDATE;
|
||||
$this->assertFalse(question_state_is_graded($state));
|
||||
|
||||
$state->event = QUESTION_EVENTSUBMIT;
|
||||
$this->assertFalse(question_state_is_graded($state));
|
||||
|
||||
$state->event = QUESTION_EVENTCLOSE;
|
||||
$this->assertFalse(question_state_is_graded($state));
|
||||
|
||||
$state->event = QUESTION_EVENTCLOSEANDGRADE;
|
||||
$this->assertTrue(question_state_is_graded($state));
|
||||
|
||||
$state->event = QUESTION_EVENTMANUALGRADE;
|
||||
$this->assertTrue(question_state_is_graded($state));
|
||||
|
||||
$state->event = QUESTION_EVENTGRADE;
|
||||
$this->assertTrue(question_state_is_graded($state));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -136,6 +136,10 @@ class web_test extends UnitTestCase {
|
||||
$this->assertEqual("\n\nAll the WORLD’S a stage.", html_to_text('<p>All the <strong>world’s</strong> a stage.</p>'));
|
||||
}
|
||||
|
||||
public function test_html_to_text_trailing_whitespace() {
|
||||
$this->assertEqual('With trailing whitespace and some more text', html_to_text("With trailing whitespace \nand some more text", 0));
|
||||
}
|
||||
|
||||
public function test_clean_text() {
|
||||
$text = "lala <applet>xx</applet>";
|
||||
$this->assertEqual($text, clean_text($text, FORMAT_PLAIN));
|
||||
@ -143,7 +147,4 @@ class web_test extends UnitTestCase {
|
||||
$this->assertEqual('lala xx', clean_text($text, FORMAT_MOODLE));
|
||||
$this->assertEqual('lala xx', clean_text($text, FORMAT_HTML));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -324,6 +324,9 @@ function upgrade_plugins($type, $startcallback, $endcallback, $verbose) {
|
||||
external_update_descriptions($component);
|
||||
events_update_definition($component);
|
||||
message_update_providers($component);
|
||||
if ($type === 'message') {
|
||||
message_update_processors($plug);
|
||||
}
|
||||
upgrade_plugin_mnet_functions($component);
|
||||
$endcallback($component, true, $verbose);
|
||||
}
|
||||
@ -357,6 +360,9 @@ function upgrade_plugins($type, $startcallback, $endcallback, $verbose) {
|
||||
external_update_descriptions($component);
|
||||
events_update_definition($component);
|
||||
message_update_providers($component);
|
||||
if ($type === 'message') {
|
||||
message_update_processors($plug);
|
||||
}
|
||||
upgrade_plugin_mnet_functions($component);
|
||||
|
||||
purge_all_caches();
|
||||
@ -387,6 +393,9 @@ function upgrade_plugins($type, $startcallback, $endcallback, $verbose) {
|
||||
external_update_descriptions($component);
|
||||
events_update_definition($component);
|
||||
message_update_providers($component);
|
||||
if ($type === 'message') {
|
||||
message_update_processors($plug);
|
||||
}
|
||||
upgrade_plugin_mnet_functions($component);
|
||||
|
||||
purge_all_caches();
|
||||
@ -895,6 +904,7 @@ function external_update_descriptions($component) {
|
||||
$service['enabled'] = empty($service['enabled']) ? 0 : $service['enabled'];
|
||||
$service['requiredcapability'] = empty($service['requiredcapability']) ? null : $service['requiredcapability'];
|
||||
$service['restrictedusers'] = !isset($service['restrictedusers']) ? 1 : $service['restrictedusers'];
|
||||
$service['shortname'] = !isset($service['shortname']) ? null : $service['shortname'];
|
||||
|
||||
$update = false;
|
||||
if ($dbservice->enabled != $service['enabled']) {
|
||||
@ -909,6 +919,23 @@ function external_update_descriptions($component) {
|
||||
$dbservice->restrictedusers = $service['restrictedusers'];
|
||||
$update = true;
|
||||
}
|
||||
//if shortname is not a PARAM_ALPHANUMEXT, fail (tested here for service update and creation)
|
||||
if (isset($service['shortname']) and
|
||||
(clean_param($service['shortname'], PARAM_ALPHANUMEXT) != $service['shortname'])) {
|
||||
throw new moodle_exception('installserviceshortnameerror', 'webservice', '', $service['shortname']);
|
||||
}
|
||||
if ($dbservice->shortname != $service['shortname']) {
|
||||
//check that shortname is unique
|
||||
if (isset($service['shortname'])) { //we currently accepts multiple shortname == null
|
||||
$existingservice = $DB->get_record('external_services',
|
||||
array('shortname' => $service['shortname']));
|
||||
if (!empty($existingservice)) {
|
||||
throw new moodle_exception('installexistingserviceshortnameerror', 'webservice', '', $service['shortname']);
|
||||
}
|
||||
}
|
||||
$dbservice->shortname = $service['shortname'];
|
||||
$update = true;
|
||||
}
|
||||
if ($update) {
|
||||
$DB->update_record('external_services', $dbservice);
|
||||
}
|
||||
@ -931,11 +958,21 @@ function external_update_descriptions($component) {
|
||||
unset($functions);
|
||||
}
|
||||
foreach ($services as $name => $service) {
|
||||
//check that shortname is unique
|
||||
if (isset($service['shortname'])) { //we currently accepts multiple shortname == null
|
||||
$existingservice = $DB->get_record('external_services',
|
||||
array('shortname' => $service['shortname']));
|
||||
if (!empty($existingservice)) {
|
||||
throw new moodle_exception('installserviceshortnameerror', 'webservice');
|
||||
}
|
||||
}
|
||||
|
||||
$dbservice = new stdClass();
|
||||
$dbservice->name = $name;
|
||||
$dbservice->enabled = empty($service['enabled']) ? 0 : $service['enabled'];
|
||||
$dbservice->requiredcapability = empty($service['requiredcapability']) ? null : $service['requiredcapability'];
|
||||
$dbservice->restrictedusers = !isset($service['restrictedusers']) ? 1 : $service['restrictedusers'];
|
||||
$dbservice->shortname = !isset($service['shortname']) ? null : $service['shortname'];
|
||||
$dbservice->component = $component;
|
||||
$dbservice->timecreated = time();
|
||||
$dbservice->id = $DB->insert_record('external_services', $dbservice);
|
||||
|
@ -2816,10 +2816,29 @@ function convert_tabrows_to_tree($tabrows, $selected, $inactive, $activated) {
|
||||
*/
|
||||
function get_docs_url($path) {
|
||||
global $CFG;
|
||||
if (!empty($CFG->docroot)) {
|
||||
return $CFG->docroot . '/' . current_language() . '/' . $path;
|
||||
// Check that $CFG->release has been set up, during installation it won't be.
|
||||
if (empty($CFG->release)) {
|
||||
// It's not there yet so look at version.php
|
||||
include($CFG->dirroot.'/version.php');
|
||||
} else {
|
||||
return 'http://docs.moodle.org/en/'.$path;
|
||||
// We can use $CFG->release and avoid having to include version.php
|
||||
$release = $CFG->release;
|
||||
}
|
||||
// Attempt to match the branch from the release
|
||||
if (preg_match('/^(.)\.(.)/', $release, $matches)) {
|
||||
// We should ALWAYS get here
|
||||
$branch = $matches[1].$matches[2];
|
||||
} else {
|
||||
// We should never get here but in case we do lets set $branch to .
|
||||
// the smart one's will know that this is the current directory
|
||||
// and the smarter ones will know that there is some smart matching
|
||||
// that will ensure people end up at the latest version of the docs.
|
||||
$branch = '.';
|
||||
}
|
||||
if (!empty($CFG->docroot)) {
|
||||
return $CFG->docroot . '/' . $branch . '/' . current_language() . '/' . $path;
|
||||
} else {
|
||||
return 'http://docs.moodle.org/'. $branch . '/en/' . $path;
|
||||
}
|
||||
}
|
||||
|
||||
|
48
local/qeupgradehelper/README.txt
Normal file
48
local/qeupgradehelper/README.txt
Normal file
@ -0,0 +1,48 @@
|
||||
This plugin can help upgrade site with a large number of question attempts from
|
||||
Moodle 2.0 to 2.1.
|
||||
|
||||
With a lot of question attempts, doing the whole conversion on upgrade is very
|
||||
slow. The plugin can help with that in various ways.
|
||||
|
||||
|
||||
To install using git, type this command in the root of your Moodle install
|
||||
git clone git://github.com/timhunt/moodle-local_qeupgradehelper.git local/qeupgradehelper
|
||||
Then add /local/qeupgradehelper to your git ignore.
|
||||
|
||||
Alternatively, download the zip from
|
||||
https://github.com/timhunt/moodle-local_qeupgradehelper/zipball/master
|
||||
unzip it into the local folder, and then rename the new folder to qeupgradehelper.
|
||||
|
||||
|
||||
When installed in a Moodle 2.0 site:
|
||||
|
||||
1. It provies a report of how much data there is to upgrade.
|
||||
|
||||
2. It can extract test-cases from the database. This can help you report bugs
|
||||
in the upgrade process to the developers.
|
||||
|
||||
3. You can set up cron to complete the conversion of quiz attempts, if you have
|
||||
configured a partial upgrade.
|
||||
|
||||
|
||||
If this plugin is present during upgrade:
|
||||
|
||||
4. then only a subset of attempts are upgraded. Read the instructions in the
|
||||
partialupgrade-example.php script.
|
||||
|
||||
|
||||
If this plugin is present in a Moodle 2.1 site after upgrade:
|
||||
|
||||
5. If not all attempts have been upgraded in a 2.1 site, then this plugin
|
||||
displays a list of how many quizzes still need to be upgraded
|
||||
|
||||
6. ... and can be used to complete the upgrade manually ...
|
||||
|
||||
7. or this plugin has a cron script that can be used to finish the upgrade
|
||||
automatically after the main upgrade has finished.
|
||||
|
||||
8. It can also reset any attempts that were upgraded (provided they have not
|
||||
subsequently been modified) so you can re-upgrade them. This may allow you to
|
||||
recover from a buggy upgrade.
|
||||
|
||||
9. Finally, you can still use the extract test-cases script to help report bugs.
|
162
local/qeupgradehelper/afterupgradelib.php
Normal file
162
local/qeupgradehelper/afterupgradelib.php
Normal file
@ -0,0 +1,162 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
/**
|
||||
* Question engine upgrade helper library code that relies on other parts of the
|
||||
* new question engine code.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
require_once($CFG->dirroot . '/question/engine/upgrade/upgradelib.php');
|
||||
|
||||
|
||||
class local_qeupgradehelper_attempt_upgrader extends question_engine_attempt_upgrader {
|
||||
public $quizid;
|
||||
public $attemptsdone = 0;
|
||||
public $attemptstodo;
|
||||
|
||||
public function __construct($quizid, $attemptstodo) {
|
||||
$this->quizid = $quizid;
|
||||
$this->attemptstodo = $attemptstodo;
|
||||
}
|
||||
|
||||
protected function get_quiz_ids() {
|
||||
return array($this->quizid => 1);
|
||||
}
|
||||
|
||||
protected function print_progress($done, $outof, $quizid) {
|
||||
}
|
||||
|
||||
protected function convert_quiz_attempt($quiz, $attempt, $questionsessionsrs, $questionsstatesrs) {
|
||||
$this->attemptsdone += 1;
|
||||
return parent::convert_quiz_attempt($quiz, $attempt, $questionsessionsrs, $questionsstatesrs);
|
||||
}
|
||||
|
||||
protected function reset_progress($done, $outof) {
|
||||
if (is_null($this->progressbar)) {
|
||||
$this->progressbar = new progress_bar('qe2reset');
|
||||
}
|
||||
|
||||
gc_collect_cycles(); // This was really helpful in PHP 5.2. Perhaps remove.
|
||||
$a = new stdClass();
|
||||
$a->done = $done;
|
||||
$a->todo = $outof;
|
||||
$this->progressbar->update($done, $outof,
|
||||
get_string('resettingquizattemptsprogress', 'local_qeupgradehelper', $a));
|
||||
}
|
||||
|
||||
protected function get_resettable_attempts($quiz) {
|
||||
global $DB;
|
||||
return $DB->get_records_sql("
|
||||
SELECT
|
||||
quiza.*
|
||||
|
||||
FROM {quiz_attempts} quiza
|
||||
LEFT JOIN (
|
||||
SELECT attempt, MAX(timestamp) AS time
|
||||
FROM {question_states}
|
||||
GROUP BY attempt
|
||||
) AS oldtimemodified ON oldtimemodified.attempt = quiza.uniqueid
|
||||
LEFT JOIN (
|
||||
SELECT qa.questionusageid, MAX(qas.timecreated) AS time
|
||||
FROM {question_attempts} qa
|
||||
JOIN {question_attempt_steps} qas ON qas.questionattemptid = qa.id
|
||||
GROUP BY qa.questionusageid
|
||||
) AS newtimemodified ON newtimemodified.questionusageid = quiza.uniqueid
|
||||
|
||||
WHERE quiza.preview = 0
|
||||
AND quiza.needsupgradetonewqe = 0
|
||||
AND (newtimemodified.time IS NULL OR oldtimemodified.time >= newtimemodified.time)
|
||||
AND quiza.quiz = :quizid", array('quizid' => $quiz->id));
|
||||
}
|
||||
|
||||
public function reset_all_resettable_attempts() {
|
||||
global $DB;
|
||||
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
|
||||
$quiz = $DB->get_record('quiz', array('id' => $this->quizid));
|
||||
$attempts = $this->get_resettable_attempts($quiz);
|
||||
foreach ($attempts as $attempt) {
|
||||
$this->reset_attempt($quiz, $attempt);
|
||||
}
|
||||
|
||||
$transaction->allow_commit();
|
||||
}
|
||||
|
||||
protected function reset_attempt($quiz, $attempt) {
|
||||
global $DB;
|
||||
|
||||
$this->attemptsdone += 1;
|
||||
$this->reset_progress($this->attemptsdone, $this->attemptstodo);
|
||||
|
||||
$questionids = explode(',', $quiz->questions);
|
||||
$slottoquestionid = array(0 => 0);
|
||||
foreach ($questionids as $questionid) {
|
||||
if ($questionid) {
|
||||
$slottoquestionid[] = $questionid;
|
||||
}
|
||||
}
|
||||
|
||||
$slotlayout = explode(',', $attempt->layout);
|
||||
$oldlayout = array();
|
||||
$ok = true;
|
||||
foreach ($slotlayout as $slot) {
|
||||
if (array_key_exists($slot, $slottoquestionid)) {
|
||||
$oldlayout[] = $slottoquestionid[$slot];
|
||||
} else if (in_array($slot, $questionids)) {
|
||||
// OK there was probably a problem during the original upgrade.
|
||||
$oldlayout[] = $slot;
|
||||
} else {
|
||||
$ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($ok) {
|
||||
$layout = implode(',', $oldlayout);
|
||||
} else {
|
||||
$layout = $attempt->layout;
|
||||
}
|
||||
|
||||
$DB->delete_records_select('question_attempt_step_data', "attemptstepid IN (
|
||||
SELECT qas.id
|
||||
FROM {question_attempts} qa
|
||||
JOIN {question_attempt_steps} qas ON qas.questionattemptid = qa.id
|
||||
WHERE questionusageid = :uniqueid)",
|
||||
array('uniqueid' => $attempt->uniqueid));
|
||||
$DB->delete_records_select('question_attempt_steps', "questionattemptid IN (
|
||||
SELECT qa.id
|
||||
FROM {question_attempts} qa
|
||||
WHERE questionusageid = :uniqueid)",
|
||||
array('uniqueid' => $attempt->uniqueid));
|
||||
$DB->delete_records('question_attempts',
|
||||
array('questionusageid' => $attempt->uniqueid));
|
||||
|
||||
$DB->set_field('question_usages', 'preferredbehaviour', 'to_be_set_later',
|
||||
array('id' => $attempt->uniqueid));
|
||||
$DB->set_field('quiz_attempts', 'layout', $layout,
|
||||
array('uniqueid' => $attempt->uniqueid));
|
||||
$DB->set_field('quiz_attempts', 'needsupgradetonewqe', 1,
|
||||
array('uniqueid' => $attempt->uniqueid));
|
||||
}
|
||||
}
|
76
local/qeupgradehelper/convertquiz.php
Normal file
76
local/qeupgradehelper/convertquiz.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Script to upgrade the attempts at a particular quiz, after confirmation.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
require_once(dirname(__FILE__) . '/../../config.php');
|
||||
require_once(dirname(__FILE__) . '/locallib.php');
|
||||
require_once(dirname(__FILE__) . '/afterupgradelib.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
$quizid = required_param('quizid', PARAM_INT);
|
||||
$confirmed = optional_param('confirmed', false, PARAM_BOOL);
|
||||
|
||||
require_login();
|
||||
require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
|
||||
local_qeupgradehelper_require_upgraded();
|
||||
|
||||
admin_externalpage_setup('qeupgradehelper', '', array(),
|
||||
local_qeupgradehelper_url('convertquiz', array('quizid' => $quizid)));
|
||||
$PAGE->navbar->add(get_string('listtodo', 'local_qeupgradehelper'),
|
||||
local_qeupgradehelper_url('listtodo'));
|
||||
$PAGE->navbar->add(get_string('convertattempts', 'local_qeupgradehelper'));
|
||||
|
||||
$renderer = $PAGE->get_renderer('local_qeupgradehelper');
|
||||
|
||||
$quizsummary = local_qeupgradehelper_get_quiz($quizid);
|
||||
if (!$quizsummary) {
|
||||
print_error('invalidquizid', 'local_qeupgradehelper',
|
||||
local_qeupgradehelper_url('listtodo'));
|
||||
}
|
||||
|
||||
$quizsummary->name = format_string($quizsummary->name);
|
||||
|
||||
if ($confirmed && data_submitted() && confirm_sesskey()) {
|
||||
// Actually do the conversion.
|
||||
echo $renderer->header();
|
||||
echo $renderer->heading(get_string(
|
||||
'upgradingquizattempts', 'local_qeupgradehelper', $quizsummary));
|
||||
|
||||
$upgrader = new local_qeupgradehelper_attempt_upgrader(
|
||||
$quizsummary->id, $quizsummary->numtoconvert);
|
||||
$upgrader->convert_all_quiz_attempts();
|
||||
|
||||
echo $renderer->heading(get_string('conversioncomplete', 'local_qeupgradehelper'));
|
||||
echo $renderer->end_of_page_link(
|
||||
new moodle_url('/mod/quiz/report.php', array('q' => $quizsummary->id)),
|
||||
get_string('gotoquizreport', 'local_qeupgradehelper'));
|
||||
echo $renderer->end_of_page_link(local_qeupgradehelper_url('listtodo'),
|
||||
get_string('listtodo', 'local_qeupgradehelper'));
|
||||
|
||||
echo $renderer->footer();
|
||||
exit;
|
||||
}
|
||||
|
||||
echo $renderer->convert_quiz_are_you_sure($quizsummary);
|
69
local/qeupgradehelper/cronsetup.php
Normal file
69
local/qeupgradehelper/cronsetup.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Script to set up cron to complete the upgrade automatically.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
require_once(dirname(__FILE__) . '/../../config.php');
|
||||
require_once(dirname(__FILE__) . '/locallib.php');
|
||||
require_once(dirname(__FILE__) . '/cronsetup_form.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
require_login();
|
||||
require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
|
||||
|
||||
admin_externalpage_setup('qeupgradehelper', '', array(),
|
||||
local_qeupgradehelper_url('cronsetup'));
|
||||
$PAGE->navbar->add(get_string('cronsetup', 'local_qeupgradehelper'));
|
||||
|
||||
$renderer = $PAGE->get_renderer('local_qeupgradehelper');
|
||||
|
||||
$form = new local_qeupgradehelper_cron_setup_form(
|
||||
new moodle_url('/local/qeupgradehelper/cronsetup.php'));
|
||||
$form->set_data(get_config('local_qeupgradehelper'));
|
||||
|
||||
if ($form->is_cancelled()) {
|
||||
redirect(local_qeupgradehelper_url('index'));
|
||||
|
||||
} else if ($fromform = $form->get_data()) {
|
||||
if ($fromform->cronenabled) {
|
||||
set_config('cronenabled', $fromform->cronenabled, 'local_qeupgradehelper');
|
||||
set_config('starthour', $fromform->starthour, 'local_qeupgradehelper');
|
||||
set_config('stophour', $fromform->stophour, 'local_qeupgradehelper');
|
||||
set_config('procesingtime', $fromform->procesingtime, 'local_qeupgradehelper');
|
||||
|
||||
} else {
|
||||
unset_config('cronenabled', 'local_qeupgradehelper');
|
||||
unset_config('starthour', 'local_qeupgradehelper');
|
||||
unset_config('stophour', 'local_qeupgradehelper');
|
||||
unset_config('procesingtime', 'local_qeupgradehelper');
|
||||
}
|
||||
redirect(local_qeupgradehelper_url('index'));
|
||||
|
||||
}
|
||||
|
||||
echo $renderer->header();
|
||||
echo $renderer->heading(get_string('cronsetup', 'local_qeupgradehelper'));
|
||||
echo $renderer->box(get_string('croninstructions', 'local_qeupgradehelper'));
|
||||
$form->display();
|
||||
echo $renderer->footer();
|
62
local/qeupgradehelper/cronsetup_form.php
Normal file
62
local/qeupgradehelper/cronsetup_form.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Settings form for cronsetup.php.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
|
||||
|
||||
/**
|
||||
* Cron setup form.
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class local_qeupgradehelper_cron_setup_form extends moodleform {
|
||||
public function definition() {
|
||||
$mform = $this->_form;
|
||||
|
||||
$mform->addElement('selectyesno', 'cronenabled',
|
||||
get_string('cronenabled', 'local_qeupgradehelper'));
|
||||
|
||||
$mform->addElement('select', 'starthour',
|
||||
get_string('cronstarthour', 'local_qeupgradehelper'), range(0, 23));
|
||||
|
||||
$mform->addElement('select', 'stophour',
|
||||
get_string('cronstophour', 'local_qeupgradehelper'),
|
||||
array_combine(range(1, 24), range(1, 24)));
|
||||
$mform->setDefault('stophour', 24);
|
||||
|
||||
$mform->addElement('duration', 'procesingtime',
|
||||
get_string('cronprocesingtime', 'local_qeupgradehelper'));
|
||||
$mform->setDefault('procesingtime', 60);
|
||||
|
||||
$mform->disabledIf('starthour', 'cronenabled', 'eq', 0);
|
||||
$mform->disabledIf('stophour', 'cronenabled', 'eq', 0);
|
||||
$mform->disabledIf('procesingtime', 'cronenabled', 'eq', 0);
|
||||
|
||||
$this->add_action_buttons();
|
||||
}
|
||||
}
|
74
local/qeupgradehelper/extracttestcase.php
Normal file
74
local/qeupgradehelper/extracttestcase.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Script to help create unit tests for the upgrade using example data from the
|
||||
* database.
|
||||
*
|
||||
* (The theory is that if the upgrade dies with an error, you can restore the
|
||||
* database from backup, and then use this script to extract the problem case
|
||||
* as a unit test. Then you can fix that unit tests. Then you can repeat the upgrade.)
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2009 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
require_once(dirname(__FILE__) . '/../../config.php');
|
||||
require_once(dirname(__FILE__) . '/locallib.php');
|
||||
require_once(dirname(__FILE__) . '/extracttestcase_form.php');
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
|
||||
require_login();
|
||||
require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
|
||||
|
||||
admin_externalpage_setup('qeupgradehelper', '', array(),
|
||||
local_qeupgradehelper_url('extracttestcase'));
|
||||
$PAGE->navbar->add(get_string('extracttestcase', 'local_qeupgradehelper'));
|
||||
|
||||
$renderer = $PAGE->get_renderer('local_qeupgradehelper');
|
||||
|
||||
$mform = new local_qeupgradehelper_extract_options_form(
|
||||
new moodle_url('/local/qeupgradehelper/extracttestcase.php'), null, 'get');
|
||||
|
||||
echo $OUTPUT->header();
|
||||
if ($fromform = $mform->get_data()) {
|
||||
$qsid = null;
|
||||
if (!empty($fromform->attemptid) && !empty($fromform->questionid)) {
|
||||
$qsid = local_qeupgradehelper_get_session_id($fromform->attemptid, $fromform->questionid);
|
||||
$name = 'qsession' . $qsid;
|
||||
|
||||
} else if (!empty($fromform->statehistory)) {
|
||||
notify('Searching ...', 'notifysuccess');
|
||||
flush();
|
||||
$qsid = local_qeupgradehelper_find_test_case($fromform->behaviour, $fromform->statehistory,
|
||||
$fromform->qtype, $fromform->extratests);
|
||||
$name = 'history' . $fromform->statehistory;
|
||||
}
|
||||
|
||||
if ($qsid) {
|
||||
local_qeupgradehelper_generate_unit_test($qsid, $name);
|
||||
} else {
|
||||
notify('No suitable attempts found.');
|
||||
}
|
||||
}
|
||||
|
||||
$mform->display();
|
||||
echo $OUTPUT->footer();
|
62
local/qeupgradehelper/extracttestcase_form.php
Normal file
62
local/qeupgradehelper/extracttestcase_form.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Settings form for extracttestcase.php.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2009 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
|
||||
|
||||
/**
|
||||
* Options form.
|
||||
* @copyright 2009 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class local_qeupgradehelper_extract_options_form extends moodleform {
|
||||
public function definition() {
|
||||
$mform = $this->_form;
|
||||
|
||||
$behaviour = array(
|
||||
'deferredfeedback' => 'Deferred feedback',
|
||||
'adaptive' => 'Adaptive',
|
||||
'adaptivenopenalty' => 'Adaptive (no penalties)',
|
||||
);
|
||||
|
||||
$qtypes = get_plugin_list('qtype');
|
||||
foreach ($qtypes as $qtype => $notused) {
|
||||
$qtypes[$qtype] = get_string($qtype, 'qtype_' . $qtype);
|
||||
}
|
||||
|
||||
$mform->addElement('header', 'h1', 'Either extract a specific question_session');
|
||||
$mform->addElement('text', 'attemptid', 'Quiz attempt id', array('size' => '10'));
|
||||
$mform->addElement('text', 'questionid', 'Question id', array('size' => '10'));
|
||||
$mform->addElement('header', 'h2', 'Or find and extract an example by type');
|
||||
$mform->addElement('select', 'behaviour', 'Behaviour', $behaviour);
|
||||
$mform->addElement('text', 'statehistory', 'State history', array('size' => '10'));
|
||||
$mform->addElement('select', 'qtype', 'Question type', $qtypes);
|
||||
$mform->addElement('text', 'extratests', 'Extra conditions', array('size' => '50'));
|
||||
$this->add_action_buttons(false, 'Create test case');
|
||||
}
|
||||
}
|
55
local/qeupgradehelper/index.php
Normal file
55
local/qeupgradehelper/index.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This plugin can help upgrade site with a large number of question attempts
|
||||
* from Moodle 2.0 to 2.1.
|
||||
*
|
||||
* This screen is the main entry-point to the plugin, it gives the admin a list
|
||||
* of options available to them.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(dirname(__FILE__) . '/../../config.php');
|
||||
require_once(dirname(__FILE__) . '/locallib.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
require_login();
|
||||
require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
|
||||
admin_externalpage_setup('qeupgradehelper');
|
||||
|
||||
$renderer = $PAGE->get_renderer('local_qeupgradehelper');
|
||||
|
||||
$actions = array();
|
||||
if (local_qeupgradehelper_is_upgraded()) {
|
||||
$detected = get_string('upgradedsitedetected', 'local_qeupgradehelper');
|
||||
$actions[] = local_qeupgradehelper_action::make('listtodo');
|
||||
$actions[] = local_qeupgradehelper_action::make('listupgraded');
|
||||
$actions[] = local_qeupgradehelper_action::make('extracttestcase');
|
||||
$actions[] = local_qeupgradehelper_action::make('cronsetup');
|
||||
|
||||
} else {
|
||||
$detected = get_string('oldsitedetected', 'local_qeupgradehelper');
|
||||
$actions[] = local_qeupgradehelper_action::make('listpreupgrade');
|
||||
$actions[] = local_qeupgradehelper_action::make('extracttestcase');
|
||||
$actions[] = local_qeupgradehelper_action::make('cronsetup');
|
||||
}
|
||||
|
||||
echo $renderer->index_page($detected, $actions);
|
83
local/qeupgradehelper/lang/en/local_qeupgradehelper.php
Normal file
83
local/qeupgradehelper/lang/en/local_qeupgradehelper.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Question engine upgrade helper langauge strings.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
$string['action'] = 'Action';
|
||||
$string['alreadydone'] = 'Everything has already been converted';
|
||||
$string['areyousure'] = 'Are you sure?';
|
||||
$string['areyousuremessage'] = 'Do you wish to proceed with upgrading all {$a->numtoconvert} attempts at quiz \'{$a->name}\' in course {$a->shortname}?';
|
||||
$string['areyousureresetmessage'] = 'Quiz \'{$a->name}\' in course {$a->shortname} has {$a->totalattempts} attempts, of which {$a->convertedattempts} were upgraded from the old system. Of those, {$a->resettableattempts} can be reset, for later re-conversion. Do you want to proceed with this?';
|
||||
$string['attemptstoconvert'] = 'Attempts needing conversion';
|
||||
$string['backtoindex'] = 'Back to the main page';
|
||||
$string['conversioncomplete'] = 'Conversion complete';
|
||||
$string['convertattempts'] = 'Convert attempts';
|
||||
$string['convertquiz'] = 'Convert attempts...';
|
||||
$string['convertedattempts'] = 'Converted attempts';
|
||||
$string['cronenabled'] = 'Cron enabled';
|
||||
$string['croninstructions'] = 'You can enable cron to automatically complete the upgrade following a partial upgrade. Cron will run between set hours on the day (according to server local time). Each time cron runs, it will process a number of attempts until Time limit amount of time has been used, then it will stop and wait for the next cron run. Even if you have set up cron, it will not do anything unless it detects that the main upgrade to 2.1 has been completed.';
|
||||
$string['cronprocesingtime'] = 'Processing time each cron run';
|
||||
$string['cronsetup'] = 'Configure cron';
|
||||
$string['cronsetup_desc'] = 'You can configure cron to complete the upgrade of quiz attempt data automatically.';
|
||||
$string['cronstarthour'] = 'Start hour';
|
||||
$string['cronstophour'] = 'Stop hour';
|
||||
$string['extracttestcase'] = 'Extract test case';
|
||||
$string['extracttestcase_desc'] = 'Use example data from the database to help create unit tests that can be used to test the upgrade.';
|
||||
$string['gotoindex'] = 'Back to the list of quizzes that can be upgraded';
|
||||
$string['gotoquizreport'] = 'Go to the reports for this quiz, to check the upgrade';
|
||||
$string['gotoresetlink'] = 'Go to the list of quizzes that can be reset';
|
||||
$string['includedintheupgrade'] = 'Included in the upgrade?';
|
||||
$string['invalidquizid'] = 'Invaid quiz id. Either the quiz does not exist, or it has no attempts to convert.';
|
||||
$string['listpreupgrade'] = 'List quizzes and attempts';
|
||||
$string['listpreupgrade_desc'] = 'This will show a report of all the quizzes on the system and how many attempts they have. This will give you an idea of the scope of the upgrade you have to do.';
|
||||
$string['listpreupgradeintro'] = 'These are the number of quiz attempts that will need to be processed when you upgrade your site. A few tens of thousands is no worry. Much beyond that and you need to think about how long the upgrade will take.';
|
||||
$string['listtodo'] = 'List quizzes still to upgrade';
|
||||
$string['listtodo_desc'] = 'This will show a report of all the quizzes on the system (if any) that have attempts that still need to be upgraded to the new question engine.';
|
||||
$string['listtodointro'] = 'These are all the quizzes with attempt data that still needs to be converted. You can convert the attempts by clicking the link.';
|
||||
$string['listupgraded'] = 'List already upgrade quizzes that can be reset';
|
||||
$string['listupgraded_desc'] = 'This will show a report of all the quizzes on the system whose attepmts have been upgraded, and where the old data is still present so the upgrade could be reset and redone.';
|
||||
$string['listupgradedintro'] = 'These are all the quizzes that have attempts that were upgraded, and where the old attempt data is so there, so they could be reset, and the upgrade re-done.';
|
||||
$string['noquizattempts'] = 'Your site does not have any quiz attempts at all!';
|
||||
$string['nothingupgradedyet'] = 'No upgraded attempts that can be reset';
|
||||
$string['notupgradedsiterequired'] = 'This script can only work before the site has been upgraded.';
|
||||
$string['numberofattempts'] = 'Number of quiz attempts';
|
||||
$string['oldsitedetected'] = 'This appears to be a site that has not yet been upgraded to include the new question engine.';
|
||||
$string['outof'] = '{$a->some} out of {$a->total}';
|
||||
$string['pluginname'] = 'Question engine upgrade helper';
|
||||
$string['pretendupgrade'] = 'Do a dry-run of the attempts upgrade';
|
||||
$string['pretendupgrade_desc'] = 'The upgrade does three things: Load the existing data from the database; transform it; then write the transformed data to the DB. This script will test the first two parts of the process.';
|
||||
$string['questionsessions'] = 'Question sessions';
|
||||
$string['quizid'] = 'Quiz id';
|
||||
$string['quizupgrade'] = 'Quiz upgrade status';
|
||||
$string['quizzesthatcanbereset'] = 'The following quizzes have converted attempts that you may be able to reset';
|
||||
$string['quizzestobeupgraded'] = 'All quizzes with attempts';
|
||||
$string['quizzeswithunconverted'] = 'The following quizzes have attempts that need to be converted';
|
||||
$string['resetquiz'] = 'Reset attempts...';
|
||||
$string['resetcomplete'] = 'Reset complete';
|
||||
$string['resettingquizattempts'] = 'Resetting quiz attempts';
|
||||
$string['resettingquizattemptsprogress'] = 'Resetting attempt {$a->done} / {$a->outof}';
|
||||
$string['upgradingquizattempts'] = 'Upgrading the attempts for quiz \'{$a->name}\' in course {$a->shortname}';
|
||||
$string['upgradedsitedetected'] = 'This appears to be a site that has been upgraded to include the new question engine.';
|
||||
$string['upgradedsiterequired'] = 'This script can only work after the site has been upgraded.';
|
||||
$string['veryoldattemtps'] = 'Your site has {$a} quiz attempts that were never completely updated during the upgrade from Moodle 1.4 to Moodle 1.5. These attempts will be dealt wiht before the main upgrade. You need to to consider the extra time required for this.';
|
74
local/qeupgradehelper/lib.php
Normal file
74
local/qeupgradehelper/lib.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Lib functions (cron) to automatically complete the question engine upgrade
|
||||
* if it was not done all at once during the main upgrade.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once (dirname(__FILE__) . '/locallib.php');
|
||||
|
||||
|
||||
/**
|
||||
* Standard cron function
|
||||
*/
|
||||
function local_qeupgradehelper_cron() {
|
||||
$settings = get_config('local_qeupgradehelper');
|
||||
if (empty($settings->cronenabled)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mtrace('qeupgradehelper: local_qeupgradehelper_cron() started at '. date('H:i:s'));
|
||||
try {
|
||||
local_qeupgradehelper_process($settings);
|
||||
} catch (Exception $e) {
|
||||
mtrace('qeupgradehelper: local_qeupgradehelper_cron() failed with an exception:');
|
||||
mtrace($e->getMessage());
|
||||
}
|
||||
mtrace('qeupgradehelper: local_qeupgradehelper_cron() finished at ' . date('H:i:s'));
|
||||
}
|
||||
|
||||
/**
|
||||
* This function does the cron process within the time range according to settings.
|
||||
*/
|
||||
function local_qeupgradehelper_process($settings) {
|
||||
if (!local_qeupgradehelper_is_upgraded()) {
|
||||
mtrace('qeupgradehelper: site not yet upgraded. Doing nothing.');
|
||||
return;
|
||||
}
|
||||
|
||||
$hour = (int) date('H');
|
||||
if ($hour < $settings->starthour || $hour >= $settings->stophour) {
|
||||
mtrace('qeupgradehelper: not between starthour and stophour, so doing nothing (hour = ' .
|
||||
$hour . ').');
|
||||
return;
|
||||
}
|
||||
|
||||
$stoptime = time() + $settings->procesingtime;
|
||||
while (time() < $stoptime) {
|
||||
mtrace('qeupgradehelper: processing ...');
|
||||
|
||||
// TODO
|
||||
mtrace('qeupgradehelper: sorry, not implemented yet.');
|
||||
return;
|
||||
}
|
||||
}
|
61
local/qeupgradehelper/listpreupgrade.php
Normal file
61
local/qeupgradehelper/listpreupgrade.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Script to show all the quizzes in the site with how many attempts they have
|
||||
* that will need to be upgraded.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
require_once(dirname(__FILE__) . '/../../config.php');
|
||||
require_once(dirname(__FILE__) . '/locallib.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
require_login();
|
||||
require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
|
||||
local_qeupgradehelper_require_not_upgraded();
|
||||
|
||||
admin_externalpage_setup('qeupgradehelper', '', array(), local_qeupgradehelper_url(''));
|
||||
$PAGE->navbar->add(get_string('listpreupgrade', 'local_qeupgradehelper'));
|
||||
|
||||
$renderer = $PAGE->get_renderer('local_qeupgradehelper');
|
||||
|
||||
$quizzes = new local_qeupgradehelper_pre_upgrade_quiz_list();
|
||||
|
||||
// Look to see if the admin has set things up to only upgrade certain attempts.
|
||||
$partialupgradefile = $CFG->dirroot . '/local/qeupgradehelper/partialupgrade.php';
|
||||
$partialupgradefunction = 'local_qeupgradehelper_get_quizzes_to_upgrade';
|
||||
if (is_readable($partialupgradefile)) {
|
||||
include_once($partialupgradefile);
|
||||
if (function_exists($partialupgradefunction)) {
|
||||
$quizzes = new local_qeupgradehelper_pre_upgrade_quiz_list_restricted(
|
||||
$partialupgradefunction());
|
||||
}
|
||||
}
|
||||
|
||||
$numveryoldattemtps = local_qeupgradehelper_get_num_very_old_attempts();
|
||||
|
||||
if ($quizzes->is_empty()) {
|
||||
echo $renderer->simple_message_page(get_string('noquizattempts', 'local_qeupgradehelper'));
|
||||
|
||||
} else {
|
||||
echo $renderer->quiz_list_page($quizzes, $numveryoldattemtps);
|
||||
}
|
49
local/qeupgradehelper/listtodo.php
Normal file
49
local/qeupgradehelper/listtodo.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Script to show all the quizzes with attempts that still need to be upgraded
|
||||
* after the main upgrade.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
require_once(dirname(__FILE__) . '/../../config.php');
|
||||
require_once(dirname(__FILE__) . '/locallib.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
require_login();
|
||||
require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
|
||||
local_qeupgradehelper_require_upgraded();
|
||||
|
||||
admin_externalpage_setup('qeupgradehelper', '', array(),
|
||||
local_qeupgradehelper_url('listtodo'));
|
||||
$PAGE->navbar->add(get_string('listtodo', 'local_qeupgradehelper'));
|
||||
|
||||
$renderer = $PAGE->get_renderer('local_qeupgradehelper');
|
||||
|
||||
$quizzes = new local_qeupgradehelper_upgradable_quiz_list();
|
||||
|
||||
if ($quizzes->is_empty()) {
|
||||
echo $renderer->simple_message_page(get_string('alreadydone', 'local_qeupgradehelper'));
|
||||
|
||||
} else {
|
||||
echo $renderer->quiz_list_page($quizzes);
|
||||
}
|
50
local/qeupgradehelper/listupgraded.php
Normal file
50
local/qeupgradehelper/listupgraded.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Script to show all the quizzes with attempts that have been upgraded
|
||||
* after the main upgrade. With an option to reset the conversion, so it can be
|
||||
* re-done if necessary.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
require_once(dirname(__FILE__) . '/../../config.php');
|
||||
require_once(dirname(__FILE__) . '/locallib.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
require_login();
|
||||
require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
|
||||
local_qeupgradehelper_require_upgraded();
|
||||
|
||||
admin_externalpage_setup('qeupgradehelper', '', array(),
|
||||
local_qeupgradehelper_url('listupgraded'));
|
||||
$PAGE->navbar->add(get_string('listupgraded', 'local_qeupgradehelper'));
|
||||
|
||||
$renderer = $PAGE->get_renderer('local_qeupgradehelper');
|
||||
|
||||
$quizzes = new local_qeupgradehelper_resettable_quiz_list();
|
||||
|
||||
if ($quizzes->is_empty()) {
|
||||
echo $renderer->simple_message_page(get_string('nothingupgradedyet', 'local_qeupgradehelper'));
|
||||
|
||||
} else {
|
||||
echo $renderer->quiz_list_page($quizzes);
|
||||
}
|
661
local/qeupgradehelper/locallib.php
Normal file
661
local/qeupgradehelper/locallib.php
Normal file
@ -0,0 +1,661 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Question engine upgrade helper library code.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Detect whether this site has been upgraded to the new question engine yet.
|
||||
* @return bool whether the site has been upgraded.
|
||||
*/
|
||||
function local_qeupgradehelper_is_upgraded() {
|
||||
global $CFG, $DB;
|
||||
$dbman = $DB->get_manager();
|
||||
return is_readable($CFG->dirroot . '/question/engine/upgrade/upgradelib.php') &&
|
||||
$dbman->table_exists('question_usages');
|
||||
}
|
||||
|
||||
/**
|
||||
* If the site has not yet been upgraded, display an error.
|
||||
*/
|
||||
function local_qeupgradehelper_require_upgraded() {
|
||||
if (!local_qeupgradehelper_is_upgraded()) {
|
||||
throw new moodle_exception('upgradedsiterequired', 'local_qeupgradehelper',
|
||||
local_qeupgradehelper_url('index'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the site has been upgraded, display an error.
|
||||
*/
|
||||
function local_qeupgradehelper_require_not_upgraded() {
|
||||
if (local_qeupgradehelper_is_upgraded()) {
|
||||
throw new moodle_exception('notupgradedsiterequired', 'local_qeupgradehelper',
|
||||
local_qeupgradehelper_url('index'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL of a script within this plugin.
|
||||
* @param string $script the script name, without .php. E.g. 'index'.
|
||||
* @param array $params URL parameters (optional).
|
||||
*/
|
||||
function local_qeupgradehelper_url($script, $params = array()) {
|
||||
return new moodle_url('/local/qeupgradehelper/' . $script . '.php', $params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class to encapsulate one of the functionalities that this plugin offers.
|
||||
*
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class local_qeupgradehelper_action {
|
||||
/** @var string the name of this action. */
|
||||
public $name;
|
||||
/** @var moodle_url the URL to launch this action. */
|
||||
public $url;
|
||||
/** @var string a description of this aciton. */
|
||||
public $description;
|
||||
|
||||
/**
|
||||
* Constructor to set the fields.
|
||||
*/
|
||||
protected function __construct($name, moodle_url $url, $description) {
|
||||
$this->name = $name;
|
||||
$this->url = $url;
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an action with standard values.
|
||||
* @param string $shortname internal name of the action. Used to get strings
|
||||
* and build a URL.
|
||||
* @param array $params any URL params required.
|
||||
*/
|
||||
public static function make($shortname, $params = array()) {
|
||||
return new self(
|
||||
get_string($shortname, 'local_qeupgradehelper'),
|
||||
local_qeupgradehelper_url($shortname, $params),
|
||||
get_string($shortname . '_desc', 'local_qeupgradehelper'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A class to represent a list of quizzes with various information about
|
||||
* attempts that can be displayed as a table.
|
||||
*
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class local_qeupgradehelper_quiz_list {
|
||||
public $title;
|
||||
public $intro;
|
||||
public $quizacolheader;
|
||||
public $sql;
|
||||
public $quizlist = null;
|
||||
public $totalquizas = 0;
|
||||
public $totalqas = 0;
|
||||
|
||||
protected function __construct($title, $intro, $quizacolheader) {
|
||||
global $DB;
|
||||
$this->title = get_string($title, 'local_qeupgradehelper');
|
||||
$this->intro = get_string($intro, 'local_qeupgradehelper');
|
||||
$this->quizacolheader = get_string($quizacolheader, 'local_qeupgradehelper');
|
||||
$this->build_sql();
|
||||
$this->quizlist = $DB->get_records_sql($this->sql);
|
||||
}
|
||||
|
||||
protected function build_sql() {
|
||||
$this->sql = '
|
||||
SELECT
|
||||
quiz.id,
|
||||
quiz.name,
|
||||
c.shortname,
|
||||
c.id AS courseid,
|
||||
COUNT(1) AS attemptcount,
|
||||
SUM(qsesscounts.num) AS questionattempts
|
||||
|
||||
FROM {quiz_attempts} quiza
|
||||
JOIN {quiz} quiz ON quiz.id = quiza.quiz
|
||||
JOIN {course} c ON c.id = quiz.course
|
||||
LEFT JOIN (
|
||||
SELECT attemptid, COUNT(1) AS num
|
||||
FROM {question_sessions}
|
||||
GROUP BY attemptid
|
||||
) qsesscounts ON qsesscounts.attemptid = quiza.uniqueid
|
||||
|
||||
WHERE quiza.preview = 0
|
||||
' . $this->extra_where_clause() . '
|
||||
|
||||
GROUP BY quiz.id, quiz.name, c.shortname, c.id
|
||||
|
||||
ORDER BY c.shortname, quiz.name, quiz.id';
|
||||
}
|
||||
|
||||
abstract protected function extra_where_clause();
|
||||
|
||||
public function get_col_headings() {
|
||||
return array(
|
||||
get_string('quizid', 'local_qeupgradehelper'),
|
||||
get_string('course'),
|
||||
get_string('pluginname', 'quiz'),
|
||||
$this->quizacolheader,
|
||||
get_string('questionsessions', 'local_qeupgradehelper'),
|
||||
);
|
||||
}
|
||||
|
||||
public function get_row($quizinfo) {
|
||||
$this->totalquizas += $quizinfo->attemptcount;
|
||||
$this->totalqas += $quizinfo->questionattempts;
|
||||
return array(
|
||||
$quizinfo->id,
|
||||
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)),
|
||||
$quizinfo->attemptcount,
|
||||
$quizinfo->questionattempts ? $quizinfo->questionattempts : 0,
|
||||
);
|
||||
}
|
||||
|
||||
public function get_row_class($quizinfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function get_total_row() {
|
||||
return array(
|
||||
'',
|
||||
html_writer::tag('b', get_string('total')),
|
||||
'',
|
||||
html_writer::tag('b', $this->totalquizas),
|
||||
html_writer::tag('b', $this->totalqas),
|
||||
);
|
||||
}
|
||||
|
||||
public function is_empty() {
|
||||
return empty($this->quizlist);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A list of quizzes that still need to be upgraded after the main upgrade.
|
||||
*
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class local_qeupgradehelper_upgradable_quiz_list extends local_qeupgradehelper_quiz_list {
|
||||
public function __construct() {
|
||||
parent::__construct('quizzeswithunconverted', 'listtodointro', 'attemptstoconvert');
|
||||
}
|
||||
|
||||
protected function extra_where_clause() {
|
||||
return 'AND quiza.needsupgradetonewqe = 1';
|
||||
}
|
||||
|
||||
public function get_col_headings() {
|
||||
$headings = parent::get_col_headings();
|
||||
$headings[] = get_string('action', 'local_qeupgradehelper');
|
||||
return $headings;
|
||||
}
|
||||
|
||||
public function get_row($quizinfo) {
|
||||
$row = parent::get_row($quizinfo);
|
||||
$row[] = html_writer::link(local_qeupgradehelper_url('convertquiz', array('quizid' => $quizinfo->id)),
|
||||
get_string('convertquiz', 'local_qeupgradehelper'));
|
||||
return $row;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A list of quizzes that still need to be upgraded after the main upgrade.
|
||||
*
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class local_qeupgradehelper_resettable_quiz_list extends local_qeupgradehelper_quiz_list {
|
||||
public function __construct() {
|
||||
parent::__construct('quizzesthatcanbereset', 'listupgradedintro', 'convertedattempts');
|
||||
}
|
||||
|
||||
protected function extra_where_clause() {
|
||||
return 'AND quiza.needsupgradetonewqe = 0
|
||||
AND EXISTS(SELECT 1 FROM {question_states}
|
||||
WHERE attempt = quiza.uniqueid)';
|
||||
}
|
||||
|
||||
public function get_col_headings() {
|
||||
$headings = parent::get_col_headings();
|
||||
$headings[] = get_string('action', 'local_qeupgradehelper');
|
||||
return $headings;
|
||||
}
|
||||
|
||||
public function get_row($quizinfo) {
|
||||
$row = parent::get_row($quizinfo);
|
||||
$row[] = html_writer::link(local_qeupgradehelper_url('resetquiz', array('quizid' => $quizinfo->id)),
|
||||
get_string('resetquiz', 'local_qeupgradehelper'));
|
||||
return $row;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A list of quizzes that will be upgraded during the main upgrade.
|
||||
*
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class local_qeupgradehelper_pre_upgrade_quiz_list extends local_qeupgradehelper_quiz_list {
|
||||
public function __construct() {
|
||||
parent::__construct('quizzestobeupgraded', 'listpreupgradeintro', 'numberofattempts');
|
||||
}
|
||||
|
||||
protected function extra_where_clause() {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A list of quizzes that will be upgraded during the main upgrade, when the
|
||||
* partialupgrade.php script is being used.
|
||||
*
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class local_qeupgradehelper_pre_upgrade_quiz_list_restricted extends local_qeupgradehelper_pre_upgrade_quiz_list {
|
||||
protected $quizids;
|
||||
protected $restrictedtotalquizas = 0;
|
||||
protected $restrictedtotalqas = 0;
|
||||
|
||||
public function __construct($quizids) {
|
||||
parent::__construct();
|
||||
$this->quizids = $quizids;
|
||||
}
|
||||
|
||||
public function get_row_class($quizinfo) {
|
||||
if (!in_array($quizinfo->id, $this->quizids)) {
|
||||
return 'dimmed';
|
||||
} else {
|
||||
return parent::get_row_class($quizinfo);
|
||||
}
|
||||
}
|
||||
|
||||
public function get_col_headings() {
|
||||
$headings = parent::get_col_headings();
|
||||
$headings[] = get_string('includedintheupgrade', 'local_qeupgradehelper');
|
||||
return $headings;
|
||||
}
|
||||
|
||||
public function get_row($quizinfo) {
|
||||
$row = parent::get_row($quizinfo);
|
||||
if (in_array($quizinfo->id, $this->quizids)) {
|
||||
$this->restrictedtotalquizas += $quizinfo->attemptcount;
|
||||
$this->restrictedtotalqas += $quizinfo->questionattempts;
|
||||
$row[] = get_string('yes');
|
||||
} else {
|
||||
$row[] = get_string('no');
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
protected function out_of($restrictedtotal, $fulltotal) {
|
||||
$a = new stdClass();
|
||||
$a->some = $a->some = html_writer::tag('b', $restrictedtotal);
|
||||
$a->total = $fulltotal;
|
||||
return get_string('outof', 'local_qeupgradehelper', $a);
|
||||
}
|
||||
|
||||
public function get_total_row() {
|
||||
return array(
|
||||
'',
|
||||
html_writer::tag('b', get_string('total')),
|
||||
'',
|
||||
$this->out_of($this->restrictedtotalquizas, $this->totalquizas),
|
||||
$this->out_of($this->restrictedtotalqas, $this->totalqas),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* List the number of quiz attempts that were never upgraded from 1.4 -> 1.5.
|
||||
* @return int the number of such attempts.
|
||||
*/
|
||||
function local_qeupgradehelper_get_num_very_old_attempts() {
|
||||
global $DB;
|
||||
return $DB->count_records_sql('
|
||||
SELECT COUNT(1)
|
||||
FROM {quiz_attempts} quiza
|
||||
WHERE uniqueid IN (
|
||||
SELECT DISTINCT qst.attempt
|
||||
FROM {question_states} qst
|
||||
LEFT JOIN {question_sessions} qsess ON
|
||||
qst.question = qsess.questionid AND qst.attempt = qsess.attemptid
|
||||
WHERE qsess.id IS NULL)');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the information about a quiz to be upgraded.
|
||||
* @param integer $quizid the quiz id.
|
||||
* @return object the information about that quiz, as for
|
||||
* {@link local_qeupgradehelper_get_upgradable_quizzes()}.
|
||||
*/
|
||||
function local_qeupgradehelper_get_quiz($quizid) {
|
||||
global $DB;
|
||||
return $DB->get_record_sql("
|
||||
SELECT
|
||||
quiz.id,
|
||||
quiz.name,
|
||||
c.shortname,
|
||||
c.id AS courseid,
|
||||
COUNT(1) AS numtoconvert
|
||||
|
||||
FROM {quiz_attempts} quiza
|
||||
JOIN {quiz} quiz ON quiz.id = quiza.quiz
|
||||
JOIN {course} c ON c.id = quiz.course
|
||||
|
||||
WHERE quiza.preview = 0
|
||||
AND quiza.needsupgradetonewqe = 1
|
||||
AND quiz.id = ?
|
||||
|
||||
GROUP BY quiz.id, quiz.name, c.shortname, c.id
|
||||
|
||||
ORDER BY c.shortname, quiz.name, quiz.id", array($quizid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the information about a quiz to be upgraded.
|
||||
* @param integer $quizid the quiz id.
|
||||
* @return object the information about that quiz, as for
|
||||
* {@link local_qeupgradehelper_get_resettable_quizzes()}, but with extra fields
|
||||
* totalattempts and resettableattempts.
|
||||
*/
|
||||
function local_qeupgradehelper_get_resettable_quiz($quizid) {
|
||||
global $DB;
|
||||
return $DB->get_record_sql("
|
||||
SELECT
|
||||
quiz.id,
|
||||
quiz.name,
|
||||
c.shortname,
|
||||
c.id AS courseid,
|
||||
COUNT(1) AS totalattempts,
|
||||
SUM(CASE WHEN quiza.needsupgradetonewqe = 0 AND
|
||||
oldtimemodified.time IS NOT NULL THEN 1 ELSE 0 END) AS convertedattempts,
|
||||
SUM(CASE WHEN quiza.needsupgradetonewqe = 0 AND
|
||||
newtimemodified.time IS NULL OR oldtimemodified.time >= newtimemodified.time
|
||||
THEN 1 ELSE 0 END) AS resettableattempts
|
||||
|
||||
FROM {quiz_attempts} quiza
|
||||
JOIN {quiz} quiz ON quiz.id = quiza.quiz
|
||||
JOIN {course} c ON c.id = quiz.course
|
||||
LEFT JOIN (
|
||||
SELECT attempt, MAX(timestamp) AS time
|
||||
FROM {question_states}
|
||||
GROUP BY attempt
|
||||
) AS oldtimemodified ON oldtimemodified.attempt = quiza.uniqueid
|
||||
LEFT JOIN (
|
||||
SELECT qa.questionusageid, MAX(qas.timecreated) AS time
|
||||
FROM {question_attempts} qa
|
||||
JOIN {question_attempt_steps} qas ON qas.questionattemptid = qa.id
|
||||
GROUP BY qa.questionusageid
|
||||
) AS newtimemodified ON newtimemodified.questionusageid = quiza.uniqueid
|
||||
|
||||
WHERE quiza.preview = 0
|
||||
AND quiz.id = ?
|
||||
|
||||
GROUP BY quiz.id, quiz.name, c.shortname, c.id", array($quizid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a question session id form a quiz attempt id and a question id.
|
||||
* @param int $attemptid a quiz attempt id.
|
||||
* @param int $questionid a question id.
|
||||
* @return int the question session id.
|
||||
*/
|
||||
function local_qeupgradehelper_get_session_id($attemptid, $questionid) {
|
||||
global $DB;
|
||||
$attempt = $DB->get_record('quiz_attempts', array('id' => $attemptid));
|
||||
if (!$attempt) {
|
||||
return null;
|
||||
}
|
||||
return $DB->get_field('question_sessions', 'id',
|
||||
array('attemptid' => $attempt->uniqueid, 'questionid' => $questionid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify the question session id of a question attempt matching certain
|
||||
* requirements.
|
||||
* @param integer $behaviour 0 = deferred feedback, 1 = interactive.
|
||||
* @param string $statehistory of states, last first. E.g. 620.
|
||||
* @param string $qtype question type.
|
||||
* @return integer question_session.id.
|
||||
*/
|
||||
function local_qeupgradehelper_find_test_case($behaviour, $statehistory, $qtype, $extratests) {
|
||||
global $DB;
|
||||
|
||||
$params = array(
|
||||
'qtype' => $qtype,
|
||||
'statehistory' => $statehistory
|
||||
);
|
||||
|
||||
if ($behaviour == 'deferredfeedback') {
|
||||
$extrawhere = '';
|
||||
$params['optionflags'] = 0;
|
||||
|
||||
} else if ($behaviour == 'adaptive') {
|
||||
$extrawhere = 'AND penaltyscheme = :penaltyscheme';
|
||||
$params['optionflags'] = 0;
|
||||
$params['penaltyscheme'] = 0;
|
||||
|
||||
} else {
|
||||
$extrawhere = 'AND penaltyscheme = :penaltyscheme';
|
||||
$params['optionflags'] = 0;
|
||||
$params['penaltyscheme'] = 1;
|
||||
}
|
||||
|
||||
$possibleids = $DB->get_records_sql_menu('
|
||||
SELECT
|
||||
qsess.id,
|
||||
1
|
||||
|
||||
FROM {question_sessions} qsess
|
||||
JOIN {question_states} qst ON qst.attempt = qsess.attemptid
|
||||
AND qst.question = qsess.questionid
|
||||
JOIN {quiz_attempts} quiza ON quiza.uniqueid = qsess.attemptid
|
||||
JOIN {quiz} quiz ON quiz.id = quiza.quiz
|
||||
JOIN {question} q ON q.id = qsess.questionid
|
||||
|
||||
WHERE q.qtype = :qtype
|
||||
AND quiz.optionflags = :optionflags
|
||||
' . $extrawhere . '
|
||||
|
||||
GROUP BY
|
||||
qsess.id
|
||||
|
||||
HAVING SUM(
|
||||
(CASE WHEN qst.event = 10 THEN 1 ELSE qst.event END) *
|
||||
POWER(10, CAST(qst.seq_number AS NUMERIC(110,0)))
|
||||
) = :statehistory' . $extratests, $params, 0, 100);
|
||||
|
||||
if (!$possibleids) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return array_rand($possibleids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grab all the data that upgrade will need for upgrading one
|
||||
* attempt at one question from the old DB.
|
||||
*/
|
||||
function local_qeupgradehelper_generate_unit_test($questionsessionid, $namesuffix) {
|
||||
global $DB;
|
||||
|
||||
$qsession = $DB->get_record('question_sessions', array('id' => $questionsessionid));
|
||||
$attempt = $DB->get_record('quiz_attempts', array('uniqueid' => $qsession->attemptid));
|
||||
$quiz = $DB->get_record('quiz', array('id' => $attempt->quiz));
|
||||
$qstates = $DB->get_records('question_states',
|
||||
array('attempt' => $qsession->attemptid, 'question' => $qsession->questionid),
|
||||
'seq_number, id');
|
||||
|
||||
$question = local_qeupgradehelper_load_question($qsession->questionid, $quiz->id);
|
||||
|
||||
if (!local_qeupgradehelper_is_upgraded()) {
|
||||
if (!$quiz->optionflags) {
|
||||
$quiz->preferredbehaviour = 'deferredfeedback';
|
||||
} else if (!$quiz->penaltyscheme) {
|
||||
$quiz->preferredbehaviour = 'adaptive';
|
||||
} else {
|
||||
$quiz->preferredbehaviour = 'adaptivenopenalty';
|
||||
}
|
||||
unset($quiz->optionflags);
|
||||
unset($quiz->penaltyscheme);
|
||||
|
||||
$question->defaultmark = $question->defaultgrade;
|
||||
unset($question->defaultgrade);
|
||||
}
|
||||
|
||||
$attempt->needsupgradetonewqe = 1;
|
||||
|
||||
echo '<textarea readonly="readonly" rows="80" cols="120" >' . "
|
||||
public function test_{$question->qtype}_{$quiz->preferredbehaviour}_{$namesuffix}() {
|
||||
";
|
||||
local_qeupgradehelper_display_convert_attempt_input($quiz, $attempt,
|
||||
$question, $qsession, $qstates);
|
||||
|
||||
if ($question->qtype == 'random') {
|
||||
list($randombit, $realanswer) = explode('-', reset($qstates)->answer, 2);
|
||||
$newquestionid = substr($randombit, 6);
|
||||
$newquestion = local_qeupgradehelper_load_question($newquestionid);
|
||||
$newquestion->maxmark = $question->maxmark;
|
||||
|
||||
echo local_qeupgradehelper_format_var('$realquestion', $newquestion);
|
||||
echo ' $this->loader->put_question_in_cache($realquestion);
|
||||
';
|
||||
}
|
||||
|
||||
echo '
|
||||
$qa = $this->updater->convert_question_attempt($quiz, $attempt, $question, $qsession, $qstates);
|
||||
|
||||
$expectedqa = (object) array(';
|
||||
echo "
|
||||
'behaviour' => '{$quiz->preferredbehaviour}',
|
||||
'questionid' => {$question->id},
|
||||
'variant' => 1,
|
||||
'maxmark' => {$question->maxmark},
|
||||
'minfraction' => 0,
|
||||
'flagged' => 0,
|
||||
'questionsummary' => '',
|
||||
'rightanswer' => '',
|
||||
'responsesummary' => '',
|
||||
'timemodified' => 0,
|
||||
'steps' => array(";
|
||||
foreach ($qstates as $state) {
|
||||
echo "
|
||||
{$state->seq_number} => (object) array(
|
||||
'sequencenumber' => {$state->seq_number},
|
||||
'state' => '',
|
||||
'fraction' => null,
|
||||
'timecreated' => {$state->timestamp},
|
||||
'userid' => {$attempt->userid},
|
||||
'data' => array(),
|
||||
),";
|
||||
}
|
||||
echo '
|
||||
),
|
||||
);
|
||||
|
||||
$this->compare_qas($expectedqa, $qa);
|
||||
}
|
||||
</textarea>';
|
||||
}
|
||||
|
||||
function local_qeupgradehelper_format_var($name, $var) {
|
||||
$out = var_export($var, true);
|
||||
$out = str_replace('<', '<', $out);
|
||||
$out = str_replace('ADOFetchObj::__set_state(array(', '(object) array(', $out);
|
||||
$out = str_replace('stdClass::__set_state(array(', '(object) array(', $out);
|
||||
$out = str_replace('array (', 'array(', $out);
|
||||
$out = preg_replace('/=> \n\s*/', '=> ', $out);
|
||||
$out = str_replace(')),', '),', $out);
|
||||
$out = str_replace('))', ')', $out);
|
||||
$out = preg_replace('/\n (?! )/', "\n ", $out);
|
||||
$out = preg_replace('/\n (?! )/', "\n ", $out);
|
||||
$out = preg_replace('/\n (?! )/', "\n ", $out);
|
||||
$out = preg_replace('/\n (?! )/', "\n ", $out);
|
||||
$out = preg_replace('/\n (?! )/', "\n ", $out);
|
||||
$out = preg_replace('/\n (?! )/', "\n ", $out);
|
||||
$out = preg_replace('/\n (?! )/', "\n ", $out);
|
||||
$out = preg_replace('/\n (?! )/', "\n ", $out);
|
||||
$out = preg_replace('/\n (?! )/', "\n ", $out);
|
||||
$out = preg_replace('/\n (?! )/', "\n ", $out);
|
||||
$out = preg_replace('/\n (?! )/', "\n ", $out);
|
||||
$out = preg_replace('/\n (?! )/', "\n ", $out);
|
||||
$out = preg_replace('/\n(?! )/', "\n ", $out);
|
||||
$out = preg_replace('/\bNULL\b/', 'null', $out);
|
||||
return " $name = $out;\n";
|
||||
}
|
||||
|
||||
function local_qeupgradehelper_display_convert_attempt_input($quiz, $attempt,
|
||||
$question, $qsession, $qstates) {
|
||||
echo local_qeupgradehelper_format_var('$quiz', $quiz);
|
||||
echo local_qeupgradehelper_format_var('$attempt', $attempt);
|
||||
echo local_qeupgradehelper_format_var('$question', $question);
|
||||
echo local_qeupgradehelper_format_var('$qsession', $qsession);
|
||||
echo local_qeupgradehelper_format_var('$qstates', $qstates);
|
||||
}
|
||||
|
||||
function local_qeupgradehelper_load_question($questionid, $quizid) {
|
||||
global $CFG, $DB;
|
||||
|
||||
$question = $DB->get_record_sql('
|
||||
SELECT q.*, qqi.grade AS maxmark
|
||||
FROM {question} q
|
||||
JOIN {quiz_question_instances} qqi ON qqi.question = q.id
|
||||
WHERE q.id = :questionid AND qqi.quiz = :quizid',
|
||||
array('questionid' => $questionid, 'quizid' => $quizid));
|
||||
|
||||
if (local_qeupgradehelper_is_upgraded()) {
|
||||
require_once($CFG->dirroot . '/question/engine/bank.php');
|
||||
$qtype = question_bank::get_qtype($question->qtype, false);
|
||||
} else {
|
||||
global $QTYPES;
|
||||
if (!array_key_exists($question->qtype, $QTYPES)) {
|
||||
$question->qtype = 'missingtype';
|
||||
$question->questiontext = '<p>' . get_string('warningmissingtype', 'quiz') . '</p>' . $question->questiontext;
|
||||
}
|
||||
$qtype = $QTYPES[$question->qtype];
|
||||
}
|
||||
|
||||
$qtype->get_question_options($question);
|
||||
|
||||
return $question;
|
||||
}
|
115
local/qeupgradehelper/partialupgrade-example.php
Normal file
115
local/qeupgradehelper/partialupgrade-example.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Example script, showing how it is possible to only do a part-upgrade of the
|
||||
* attempt data during the main upgrade, and then finish the job off later.
|
||||
*
|
||||
* If you want to use this facility, then you need to:
|
||||
*
|
||||
* 1. Rename this script to partialupgrade.php.
|
||||
* 2. Look at the various example functions below for controlling the upgrade,
|
||||
* chooose one you like, and un-comment it. Alternatively, write your own
|
||||
* custom function.
|
||||
* 3. Use the List quizzes and attempts options in this plugin, which should now
|
||||
* display updated information.
|
||||
* 4. Once you are sure that works, you can proceed with the upgrade as usual.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* This is a very simple example that just uses a hard-coded array to control
|
||||
* which attempts are upgraded.
|
||||
*
|
||||
* @return array of quiz ids that are the ones to upgrade during the main
|
||||
* upgrade from 2.0 to 2.1. Attempts at other quizzes are left alone, you will
|
||||
* have to take steps to upgrade them yourself using the facilities provided by
|
||||
* this plugin.
|
||||
*/
|
||||
//function local_qeupgradehelper_get_quizzes_to_upgrade() {
|
||||
// return array(1, 2, 3);
|
||||
//}
|
||||
|
||||
|
||||
/**
|
||||
* This example function uses a list of quiz ids from a file.
|
||||
*
|
||||
* It is currently set to use the file quiz-ids-to-upgrade.txt in the same
|
||||
* folder as this script, but you can change that if you like.
|
||||
*
|
||||
* That file should contain one quiz id per line, with no punctuation. Any line
|
||||
* that does not look like an integer is ignored.
|
||||
*
|
||||
* @return array of quiz ids that are the ones to upgrade during the main
|
||||
* upgrade from 2.0 to 2.1. Attempts at other quizzes are left alone, you will
|
||||
* have to take steps to upgrade them yourself using the facilities provided by
|
||||
* this plugin.
|
||||
*/
|
||||
//function local_qeupgradehelper_get_quizzes_to_upgrade() {
|
||||
// global $CFG;
|
||||
// $rawids = file($CFG->dirroot . '/local/qeupgradehelper/quiz-ids-to-upgrade.txt');
|
||||
// $cleanids = array();
|
||||
// foreach ($rawids as $id) {
|
||||
// $id = clean_param($id, PARAM_INT);
|
||||
// if ($id) {
|
||||
// $cleanids[] = $id;
|
||||
// }
|
||||
// }
|
||||
// return $cleanids;
|
||||
//}
|
||||
|
||||
|
||||
/**
|
||||
* This example uses a complex SQL query to decide which attempts to upgrade.
|
||||
*
|
||||
* The particular example I have done here is to return the ids of all the quizzes
|
||||
* in courses that started more recently than one year ago. Of coures, you can
|
||||
* write any query you like to meet your needs.
|
||||
*
|
||||
* Remember that you can use the List quizzes and attempts options option provided
|
||||
* by this plugin to verify that your query is selecting the quizzes you intend.
|
||||
*
|
||||
* @return array of quiz ids that are the ones to upgrade during the main
|
||||
* upgrade from 2.0 to 2.1. Attempts at other quizzes are left alone, you will
|
||||
* have to take steps to upgrade them yourself using the facilities provided by
|
||||
* this plugin.
|
||||
*/
|
||||
//function local_qeupgradehelper_get_quizzes_to_upgrade() {
|
||||
// global $DB;
|
||||
//
|
||||
// $quizmoduleid = $DB->get_field('modules', 'id', array('name' => 'quiz'));
|
||||
//
|
||||
// $oneyearago = strtotime('-1 year');
|
||||
//
|
||||
// return $DB->get_fieldset_sql('
|
||||
// SELECT DISTINCT quiz.id
|
||||
//
|
||||
// FROM {quiz} quiz
|
||||
// JOIN {course_modules} cm ON cm.module = :quizmoduleid
|
||||
// AND cm.instance = quiz.id
|
||||
// JOIN {course} c ON quiz.course = c.id
|
||||
//
|
||||
// WHERE c.startdate > :cutoffdate
|
||||
//
|
||||
// ORDER BY quiz.id
|
||||
// ', array('quizmoduleid' => $quizmoduleid, 'cutoffdate' => $oneyearago));
|
||||
// ");
|
||||
//}
|
168
local/qeupgradehelper/renderer.php
Normal file
168
local/qeupgradehelper/renderer.php
Normal file
@ -0,0 +1,168 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Defines the renderer for the question engine upgrade helper plugin.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Renderer for the question engine upgrade helper plugin.
|
||||
*
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class local_qeupgradehelper_renderer extends plugin_renderer_base {
|
||||
|
||||
/**
|
||||
* Render the index page.
|
||||
* @param string $detected information about what sort of site was detected.
|
||||
* @param array $actions list of actions to show on this page.
|
||||
* @return string html to output.
|
||||
*/
|
||||
public function index_page($detected, array $actions) {
|
||||
$output = '';
|
||||
$output .= $this->header();
|
||||
$output .= $this->heading(get_string('pluginname', 'local_qeupgradehelper'));
|
||||
$output .= $this->box($detected);
|
||||
$output .= html_writer::start_tag('ul');
|
||||
foreach ($actions as $action) {
|
||||
$output .= html_writer::tag('li',
|
||||
html_writer::link($action->url, $action->name) . ' - ' .
|
||||
$action->description);
|
||||
}
|
||||
$output .= html_writer::end_tag('ul');
|
||||
$output .= $this->footer();
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a page that is just a simple message.
|
||||
* @param string $message the message to display.
|
||||
* @return string html to output.
|
||||
*/
|
||||
public function simple_message_page($message) {
|
||||
$output = '';
|
||||
$output .= $this->header();
|
||||
$output .= $this->heading($message);
|
||||
$output .= $this->back_to_index();
|
||||
$output .= $this->footer();
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the list of quizzes that still need to be upgraded page.
|
||||
* @param array $quizzes of data about quizzes.
|
||||
* @param int $numveryoldattemtps only relevant before upgrade.
|
||||
* @return string html to output.
|
||||
*/
|
||||
public function quiz_list_page(local_qeupgradehelper_quiz_list $quizzes,
|
||||
$numveryoldattemtps = null) {
|
||||
$output = '';
|
||||
$output .= $this->header();
|
||||
$output .= $this->heading($quizzes->title);
|
||||
$output .= $this->box($quizzes->intro);
|
||||
|
||||
$table = new html_table();
|
||||
$table->head = $quizzes->get_col_headings();
|
||||
|
||||
$rowcount = 0;
|
||||
foreach ($quizzes->quizlist as $quizinfo) {
|
||||
$table->data[$rowcount] = $quizzes->get_row($quizinfo);
|
||||
if ($class = $quizzes->get_row_class($quizinfo)) {
|
||||
$table->rowclasses[$rowcount] = $class;
|
||||
}
|
||||
$rowcount += 1;
|
||||
}
|
||||
$table->data[] = $quizzes->get_total_row();
|
||||
$output .= html_writer::table($table);
|
||||
|
||||
if ($numveryoldattemtps) {
|
||||
$output .= $this->box(get_string('veryoldattemtps', 'local_qeupgradehelper',
|
||||
$numveryoldattemtps));
|
||||
}
|
||||
|
||||
$output .= $this->back_to_index();
|
||||
$output .= $this->footer();
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the are-you-sure page to confirm a manual upgrade.
|
||||
* @param object $quizsummary data about the quiz to upgrade.
|
||||
* @return string html to output.
|
||||
*/
|
||||
public function convert_quiz_are_you_sure($quizsummary) {
|
||||
$output = '';
|
||||
$output .= $this->header();
|
||||
$output .= $this->heading(get_string('areyousure', 'local_qeupgradehelper'));
|
||||
|
||||
$params = array('quizid' => $quizsummary->id, 'confirmed' => 1, 'sesskey' => sesskey());
|
||||
$output .= $this->confirm(get_string('areyousuremessage', 'local_qeupgradehelper', $quizsummary),
|
||||
new single_button(local_qeupgradehelper_url('convertquiz', $params), get_string('yes')),
|
||||
local_qeupgradehelper_url('listtodo'));
|
||||
|
||||
$output .= $this->footer();
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the are-you-sure page to confirm a manual reset.
|
||||
* @param object $quizsummary data about the quiz to reset.
|
||||
* @return string html to output.
|
||||
*/
|
||||
public function reset_quiz_are_you_sure($quizsummary) {
|
||||
$output = '';
|
||||
$output .= $this->header();
|
||||
$output .= $this->heading(get_string('areyousure', 'local_qeupgradehelper'));
|
||||
|
||||
$params = array('quizid' => $quizsummary->id, 'confirmed' => 1, 'sesskey' => sesskey());
|
||||
$output .= $this->confirm(get_string('areyousureresetmessage', 'local_qeupgradehelper', $quizsummary),
|
||||
new single_button(local_qeupgradehelper_url('resetquiz', $params), get_string('yes')),
|
||||
local_qeupgradehelper_url('listupgraded'));
|
||||
|
||||
$output .= $this->footer();
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a link in a div, such as the 'Back to plugin main page' link.
|
||||
* @param $url the link URL.
|
||||
* @param $text the link text.
|
||||
* @return string html to output.
|
||||
*/
|
||||
public function end_of_page_link($url, $text) {
|
||||
return html_writer::tag('div', html_writer::link($url ,$text),
|
||||
array('class' => 'mdl-align'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a link back to the plugin index page.
|
||||
* @return string html to output.
|
||||
*/
|
||||
public function back_to_index() {
|
||||
return $this->end_of_page_link(local_qeupgradehelper_url('index'),
|
||||
get_string('backtoindex', 'local_qeupgradehelper'));
|
||||
}
|
||||
}
|
72
local/qeupgradehelper/resetquiz.php
Normal file
72
local/qeupgradehelper/resetquiz.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Script to reset the upgrade of attempts at a particular quiz, after confirmation.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(dirname(__FILE__) . '/../../config.php');
|
||||
require_once(dirname(__FILE__) . '/locallib.php');
|
||||
require_once(dirname(__FILE__) . '/afterupgradelib.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
$quizid = required_param('quizid', PARAM_INT);
|
||||
$confirmed = optional_param('confirmed', false, PARAM_BOOL);
|
||||
|
||||
require_login();
|
||||
require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
|
||||
local_qeupgradehelper_require_upgraded();
|
||||
|
||||
admin_externalpage_setup('qeupgradehelper', '', array(),
|
||||
local_qeupgradehelper_url('resetquiz', array('quizid' => $quizid)));
|
||||
$PAGE->navbar->add(get_string('listupgraded', 'local_qeupgradehelper'),
|
||||
local_qeupgradehelper_url('listtodo'));
|
||||
$PAGE->navbar->add(get_string('resetquiz', 'local_qeupgradehelper'));
|
||||
|
||||
$renderer = $PAGE->get_renderer('local_qeupgradehelper');
|
||||
|
||||
$quizsummary = local_qeupgradehelper_get_resettable_quiz($quizid);
|
||||
if (!$quizsummary) {
|
||||
print_error('invalidquizid', 'local_qeupgradehelper',
|
||||
local_qeupgradehelper_url('listupgraded'));
|
||||
}
|
||||
|
||||
$quizsummary->name = format_string($quizsummary->name);
|
||||
|
||||
if ($confirmed && data_submitted() && confirm_sesskey()) {
|
||||
// Actually do the conversion.
|
||||
echo $renderer->header();
|
||||
echo $renderer->heading(get_string(
|
||||
'resettingquizattempts', 'local_qeupgradehelper', $quizsummary));
|
||||
|
||||
$upgrader = new local_qeupgradehelper_attempt_upgrader(
|
||||
$quizsummary->id, $quizsummary->resettableattempts);
|
||||
$upgrader->reset_all_resettable_attempts();
|
||||
|
||||
echo $renderer->heading(get_string('resetcomplete', 'local_qeupgradehelper'));
|
||||
echo $renderer->end_of_page_link(local_qeupgradehelper_url('listupgraded'),
|
||||
get_string('listupgraded', 'local_qeupgradehelper'));
|
||||
|
||||
echo $renderer->footer();
|
||||
exit;
|
||||
}
|
||||
|
||||
echo $renderer->reset_quiz_are_you_sure($quizsummary);
|
32
local/qeupgradehelper/settings.php
Normal file
32
local/qeupgradehelper/settings.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Adds this plugin to the admin menu.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
if ($hassiteconfig) { // needs this condition or there is error on login page
|
||||
$ADMIN->add('root', new admin_externalpage('qeupgradehelper',
|
||||
get_string('pluginname', 'local_qeupgradehelper'),
|
||||
new moodle_url('/local/qeupgradehelper/index.php')));
|
||||
}
|
6
local/qeupgradehelper/styles.css
Normal file
6
local/qeupgradehelper/styles.css
Normal file
@ -0,0 +1,6 @@
|
||||
#page-admin-local-qeupgradehelper-index .dimmed {
|
||||
color: grey;
|
||||
}
|
||||
#page-admin-local-qeupgradehelper-index .dimmed a {
|
||||
color: #88c;
|
||||
}
|
29
local/qeupgradehelper/version.php
Normal file
29
local/qeupgradehelper/version.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Version details.
|
||||
*
|
||||
* @package local
|
||||
* @subpackage qeupgradehelper
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
$plugin->version = 2011040400;
|
||||
$plugin->requires = 2010080300;
|
115
message/defaultoutputs.php
Normal file
115
message/defaultoutputs.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Default message outputs configuration page
|
||||
*
|
||||
* @package message
|
||||
* @copyright 2011 Lancaster University Network Services Limited
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/../config.php');
|
||||
require_once($CFG->dirroot . '/message/lib.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
|
||||
// This is an admin page
|
||||
admin_externalpage_setup('defaultmessageoutputs');
|
||||
|
||||
// Require site configuration capability
|
||||
require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
|
||||
|
||||
// Fetch processors
|
||||
$processors = get_message_processors(true);
|
||||
// Fetch message providers
|
||||
$providers = $DB->get_records('message_providers', null, 'name');
|
||||
|
||||
if (($form = data_submitted()) && confirm_sesskey()) {
|
||||
$preferences = array();
|
||||
// Prepare default message outputs settings
|
||||
foreach ( $providers as $provider) {
|
||||
$componentproviderbase = $provider->component.'_'.$provider->name;
|
||||
foreach (array('permitted', 'loggedin', 'loggedoff') as $setting){
|
||||
$value = null;
|
||||
$componentprovidersetting = $componentproviderbase.'_'.$setting;
|
||||
if ($setting == 'permitted') {
|
||||
// if we deal with permitted select element, we need to create individual
|
||||
// setting for each possible processor. Note that this block will
|
||||
// always be processed first after entring parental foreach iteration
|
||||
// so we can change form values on this stage.
|
||||
foreach($processors as $processor) {
|
||||
$value = '';
|
||||
if (isset($form->{$componentprovidersetting}[$processor->name])) {
|
||||
$value = $form->{$componentprovidersetting}[$processor->name];
|
||||
}
|
||||
// Ensure that loggedin loggedoff options are set correctly
|
||||
// for this permission
|
||||
if ($value == 'forced') {
|
||||
$form->{$componentproviderbase.'_loggedin'}[$processor->name] = 1;
|
||||
$form->{$componentproviderbase.'_loggedoff'}[$processor->name] = 1;
|
||||
} else if ($value == 'disallowed') {
|
||||
// It might be better to unset them, but I can't figure out why that cause error
|
||||
$form->{$componentproviderbase.'_loggedin'}[$processor->name] = 0;
|
||||
$form->{$componentproviderbase.'_loggedoff'}[$processor->name] = 0;
|
||||
}
|
||||
// record the site preference
|
||||
$preferences[$processor->name.'_provider_'.$componentprovidersetting] = $value;
|
||||
}
|
||||
} else if (array_key_exists($componentprovidersetting, $form)) {
|
||||
// we must be processing loggedin or loggedoff checkboxes. Store
|
||||
// defained comma-separated processors as setting value.
|
||||
// Using array_filter eliminates elements set to 0 above
|
||||
$value = join(',', array_keys(array_filter($form->{$componentprovidersetting})));
|
||||
if (empty($value)) {
|
||||
$value = null;
|
||||
}
|
||||
}
|
||||
if ($setting != 'permitted') {
|
||||
// we have already recoded site preferences for 'permitted' type
|
||||
$preferences['message_provider_'.$componentprovidersetting] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update database
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
foreach ($preferences as $name => $value) {
|
||||
set_config($name, $value, 'message');
|
||||
}
|
||||
$transaction->allow_commit();
|
||||
|
||||
// Redirect
|
||||
$url = new moodle_url('defaultoutputs.php');
|
||||
redirect($url);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Page settings
|
||||
$PAGE->set_context(get_context_instance(CONTEXT_SYSTEM));
|
||||
$PAGE->requires->js_init_call('M.core_message.init_defaultoutputs');
|
||||
|
||||
// Grab the renderer
|
||||
$renderer = $PAGE->get_renderer('core', 'message');
|
||||
|
||||
// Display the manage message outputs interface
|
||||
$preferences = get_message_output_default_preferences();
|
||||
$messageoutputs = $renderer->manage_defaultmessageoutputs($processors, $providers, $preferences);
|
||||
|
||||
// Display the page
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('defaultmessageoutputs', 'message'));
|
||||
echo $messageoutputs;
|
||||
echo $OUTPUT->footer();
|
149
message/edit.php
149
message/edit.php
@ -23,7 +23,8 @@
|
||||
* @package message
|
||||
*/
|
||||
|
||||
require_once('../config.php');
|
||||
require_once(dirname(__FILE__) . '/../config.php');
|
||||
require_once($CFG->dirroot . '/message/lib.php');
|
||||
|
||||
$userid = optional_param('id', $USER->id, PARAM_INT); // user id
|
||||
$course = optional_param('course', SITEID, PARAM_INT); // course id (defaults to Site)
|
||||
@ -97,13 +98,13 @@ if (($form = data_submitted()) && confirm_sesskey()) {
|
||||
|
||||
/// Set all the preferences for all the message providers
|
||||
$providers = message_get_my_providers();
|
||||
$possiblestates = array('loggedin', 'loggedoff');
|
||||
foreach ( $providers as $providerid => $provider){
|
||||
foreach ($possiblestates as $state){
|
||||
foreach ($providers as $provider) {
|
||||
$componentproviderbase = $provider->component.'_'.$provider->name;
|
||||
foreach (array('loggedin', 'loggedoff') as $state) {
|
||||
$linepref = '';
|
||||
$componentproviderstate = $provider->component.'_'.$provider->name.'_'.$state;
|
||||
$componentproviderstate = $componentproviderbase.'_'.$state;
|
||||
if (array_key_exists($componentproviderstate, $form)) {
|
||||
foreach ($form->{$componentproviderstate} as $process=>$one){
|
||||
foreach (array_keys($form->{$componentproviderstate}) as $process){
|
||||
if ($linepref == ''){
|
||||
$linepref = $process;
|
||||
} else {
|
||||
@ -111,33 +112,17 @@ if (($form = data_submitted()) && confirm_sesskey()) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty($linepref)) {
|
||||
$linepref = 'none';
|
||||
}
|
||||
$preferences['message_provider_'.$provider->component.'_'.$provider->name.'_'.$state] = $linepref;
|
||||
}
|
||||
}
|
||||
foreach ( $providers as $providerid => $provider){
|
||||
foreach ($possiblestates as $state){
|
||||
$preferencekey = 'message_provider_'.$provider->component.'_'.$provider->name.'_'.$state;
|
||||
if (empty($preferences[$preferencekey])) {
|
||||
$preferences[$preferencekey] = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set all the processor options as well
|
||||
$processors = $DB->get_records('message_processors');
|
||||
foreach ( $processors as $processorid => $processor){
|
||||
$processorfile = $CFG->dirroot. '/message/output/'.$processor->name.'/message_output_'.$processor->name.'.php';
|
||||
if ( is_readable($processorfile) ) {
|
||||
include_once( $processorfile );
|
||||
|
||||
$processclass = 'message_output_' . $processor->name;
|
||||
if ( class_exists($processclass) ){
|
||||
$pclass = new $processclass();
|
||||
$pclass->process_form($form, $preferences);
|
||||
} else{
|
||||
print_error('errorcallingprocessor', 'message');
|
||||
}
|
||||
}
|
||||
$processors = get_message_processors(true);
|
||||
foreach ($processors as $processor) {
|
||||
$processor->object->process_form($form, $preferences);
|
||||
}
|
||||
|
||||
//process general messaging preferences
|
||||
@ -145,7 +130,7 @@ if (($form = data_submitted()) && confirm_sesskey()) {
|
||||
//$preferences['message_beepnewmessage'] = !empty($form->beepnewmessage)?1:0;
|
||||
|
||||
// Save all the new preferences to the database
|
||||
if (!set_user_preferences( $preferences, $user->id ) ){
|
||||
if (!set_user_preferences($preferences, $user->id)) {
|
||||
print_error('cannotupdateusermsgpref');
|
||||
}
|
||||
|
||||
@ -158,34 +143,25 @@ $preferences->userdefaultemail = $user->email;//may be displayed by the email pr
|
||||
|
||||
/// Get providers preferences
|
||||
$providers = message_get_my_providers();
|
||||
foreach ( $providers as $providerid => $provider){
|
||||
foreach (array('loggedin', 'loggedoff') as $state){
|
||||
foreach ($providers as $provider) {
|
||||
foreach (array('loggedin', 'loggedoff') as $state) {
|
||||
$linepref = get_user_preferences('message_provider_'.$provider->component.'_'.$provider->name.'_'.$state, '', $user->id);
|
||||
if ($linepref == ''){
|
||||
continue;
|
||||
}
|
||||
$lineprefarray = explode(',', $linepref);
|
||||
$preferences->{$provider->component.'_'.$provider->name.'_'.$state} = array();
|
||||
foreach ($lineprefarray as $pref){
|
||||
foreach ($lineprefarray as $pref) {
|
||||
$preferences->{$provider->component.'_'.$provider->name.'_'.$state}[$pref] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load all processors
|
||||
$processors = get_message_processors();
|
||||
/// For every processors put its options on the form (need to get function from processor's lib.php)
|
||||
$processors = $DB->get_records('message_processors');
|
||||
foreach ( $processors as $processorid => $processor){
|
||||
$processorfile = $CFG->dirroot. '/message/output/'.$processor->name.'/message_output_'.$processor->name.'.php';
|
||||
if ( is_readable($processorfile) ) {
|
||||
include_once( $processorfile );
|
||||
$processclass = 'message_output_' . $processor->name;
|
||||
if ( class_exists($processclass) ){
|
||||
$pclass = new $processclass();
|
||||
$pclass->load_data($preferences, $user->id);
|
||||
} else{
|
||||
print_error('errorcallingprocessor', 'message');
|
||||
}
|
||||
}
|
||||
foreach ($processors as $processor) {
|
||||
$processor->object->load_data($preferences, $user->id);
|
||||
}
|
||||
|
||||
//load general messaging preferences
|
||||
@ -203,84 +179,17 @@ if ($course->id != SITEID) {
|
||||
} else {
|
||||
$PAGE->set_heading($course->fullname);
|
||||
}
|
||||
echo $OUTPUT->header();
|
||||
|
||||
// Start the form. We're not using mform here because of our special formatting needs ...
|
||||
echo '<form class="mform" method="post" action="'.$PAGE->url.'">';
|
||||
|
||||
/// Settings table...
|
||||
echo '<fieldset id="providers" class="clearfix">';
|
||||
echo '<legend class="ftoggler">'.get_string('providers_config', 'message').'</legend>';
|
||||
// Grab the renderer
|
||||
$renderer = $PAGE->get_renderer('core', 'message');
|
||||
// Fetch message providers
|
||||
$providers = message_get_my_providers();
|
||||
$processors = $DB->get_records('message_processors', null, 'name DESC');
|
||||
$number_procs = count($processors);
|
||||
echo '<table cellpadding="2"><tr><td> </td>'."\n";
|
||||
foreach ( $processors as $processorid => $processor){
|
||||
echo '<th align="center">'.get_string('pluginname', 'message_'.$processor->name).'</th>';
|
||||
}
|
||||
echo '</tr>';
|
||||
// Fetch default (site) preferences
|
||||
$defaultpreferences = get_message_output_default_preferences();
|
||||
|
||||
foreach ( $providers as $providerid => $provider){
|
||||
$providername = get_string('messageprovider:'.$provider->name, $provider->component);
|
||||
|
||||
echo '<tr><th align="right">'.$providername.'</th><td colspan="'.$number_procs.'"></td></tr>'."\n";
|
||||
foreach (array('loggedin', 'loggedoff') as $state){
|
||||
$state_res = get_string($state.'description', 'message');
|
||||
echo '<tr><td align="right">'.$state_res.'</td>'."\n";
|
||||
foreach ( $processors as $processorid => $processor) {
|
||||
if (!isset($preferences->{$provider->component.'_'.$provider->name.'_'.$state})) {
|
||||
$checked = '';
|
||||
} else if (!isset($preferences->{$provider->component.'_'.$provider->name.'_'.$state}[$processor->name])) {
|
||||
$checked = '';
|
||||
} else {
|
||||
$checked = $preferences->{$provider->component.'_'.$provider->name.'_'.$state}[$processor->name]==1?" checked=\"checked\"":"";
|
||||
}
|
||||
echo '<td align="center"><input type="checkbox" name="'.$provider->component.'_'.$provider->name.'_'.$state.'['.$processor->name.']" '.$checked.' /></td>'."\n";
|
||||
}
|
||||
echo '</tr>'."\n";
|
||||
}
|
||||
}
|
||||
echo '</table>';
|
||||
echo '</fieldset>';
|
||||
|
||||
/// Show all the message processors
|
||||
$processors = $DB->get_records('message_processors');
|
||||
|
||||
$processorconfigform = null;
|
||||
foreach ($processors as $processorid => $processor) {
|
||||
$processorfile = $CFG->dirroot. '/message/output/'.$processor->name.'/message_output_'.$processor->name.'.php';
|
||||
if (is_readable($processorfile)) {
|
||||
include_once($processorfile);
|
||||
$processclass = 'message_output_' . $processor->name;
|
||||
|
||||
if (class_exists($processclass)) {
|
||||
$pclass = new $processclass();
|
||||
$processorconfigform = $pclass->config_form($preferences);
|
||||
|
||||
if (!empty($processorconfigform)) {
|
||||
echo '<fieldset id="messageprocessor_'.$processor->name.'" class="clearfix">';
|
||||
echo '<legend class="ftoggler">'.get_string('pluginname', 'message_'.$processor->name).'</legend>';
|
||||
|
||||
echo $processorconfigform;
|
||||
|
||||
echo '</fieldset>';
|
||||
}
|
||||
} else{
|
||||
print_error('errorcallingprocessor', 'message');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo '<fieldset id="messageprocessor_general" class="clearfix">';
|
||||
echo '<legend class="ftoggler">'.get_string('generalsettings','admin').'</legend>';
|
||||
echo get_string('blocknoncontacts', 'message').': <input type="checkbox" name="blocknoncontacts" '.($preferences->blocknoncontacts==1?' checked="checked"':'');
|
||||
//get_string('beepnewmessage', 'message').': <input type="checkbox" name="beepnewmessage" '.($preferences->beepnewmessage==1?" checked=\"checked\"":"").' />';
|
||||
echo '</fieldset>';
|
||||
|
||||
echo '<div><input type="hidden" name="sesskey" value="'.sesskey().'" /></div>';
|
||||
echo '<div style="text-align:center"><input name="submit" value="'. get_string('updatemyprofile') .'" type="submit" /></div>';
|
||||
|
||||
echo "</form>";
|
||||
$messagingoptions = $renderer->manage_messagingoptions($processors, $providers, $preferences, $defaultpreferences);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $messagingoptions;
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
|
159
message/externallib.php
Normal file
159
message/externallib.php
Normal file
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* External message API
|
||||
*
|
||||
* @package moodlecore
|
||||
* @subpackage message
|
||||
* @copyright 2011 Moodle Pty Ltd (http://moodle.com)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
require_once("$CFG->libdir/externallib.php");
|
||||
|
||||
class moodle_message_external extends external_api {
|
||||
|
||||
/**
|
||||
* Returns description of method parameters
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function send_messages_parameters() {
|
||||
return new external_function_parameters(
|
||||
array(
|
||||
'messages' => new external_multiple_structure(
|
||||
new external_single_structure(
|
||||
array(
|
||||
'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
|
||||
'text' => new external_value(PARAM_RAW, 'the text of the message - not that you can send anything it will be automatically cleaned to PARAM_TEXT and used againt MOODLE_FORMAT'),
|
||||
'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own client id for the message. If this id is provided, the fail message id will be returned to you', VALUE_OPTIONAL),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send private messages from the current USER to other users
|
||||
*
|
||||
* @param $messages An array of message to send.
|
||||
* @return boolean
|
||||
*/
|
||||
public static function send_messages($messages = array()) {
|
||||
global $CFG, $USER, $DB;
|
||||
require_once($CFG->dirroot . "/message/lib.php");
|
||||
|
||||
//check if messaging is enabled
|
||||
if (!$CFG->messaging) {
|
||||
throw new moodle_exception('disabled', 'message');
|
||||
}
|
||||
|
||||
// Ensure the current user is allowed to run this function
|
||||
$context = get_context_instance(CONTEXT_SYSTEM);
|
||||
self::validate_context($context);
|
||||
require_capability('moodle/site:sendmessage', $context);
|
||||
|
||||
$params = self::validate_parameters(self::send_messages_parameters(), array('messages' => $messages));
|
||||
|
||||
//retrieve all tousers of the messages
|
||||
$touserids = array();
|
||||
foreach($params['messages'] as $message) {
|
||||
$touserids[] = $message['touserid'];
|
||||
}
|
||||
list($sqluserids, $sqlparams) = $DB->get_in_or_equal($touserids, SQL_PARAMS_NAMED, 'userid_');
|
||||
$tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
|
||||
|
||||
//retrieve the tousers who are blocking the $USER
|
||||
$sqlparams['contactid'] = $USER->id;
|
||||
$sqlparams['blocked'] = 1;
|
||||
//Note: return userid field should be unique for the below request,
|
||||
//so we'll use this field as key of $blockingcontacts
|
||||
$blockingcontacts = $DB->get_records_select("message_contacts",
|
||||
"userid " . $sqluserids . " AND contactid = :contactid AND blocked = :blocked",
|
||||
$sqlparams, '', "userid");
|
||||
|
||||
$canreadallmessages = has_capability('moodle/site:readallmessages', $context);
|
||||
|
||||
$resultmessages = array();
|
||||
foreach ($params['messages'] as $message) {
|
||||
$text = clean_param($message['text'], PARAM_TEXT);
|
||||
$resultmsg = array(); //the infos about the success of the operation
|
||||
|
||||
//we are going to do some checking
|
||||
//code should match /messages/index.php checks
|
||||
$success = true;
|
||||
|
||||
//check the user exists
|
||||
if (empty($tousers[$message['touserid']])) {
|
||||
$success = false;
|
||||
$errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
|
||||
}
|
||||
|
||||
//check that the touser is not blocking the current user
|
||||
if ($success and isset($blockingcontacts[$message['touserid']]) and !$canreadallmessages) {
|
||||
$success = false;
|
||||
$errormessage = get_string('userisblockingyou', 'message');
|
||||
}
|
||||
|
||||
// Check if the user is a contact
|
||||
//TODO: performance improvement - edit the function so we can pass an array instead userid
|
||||
if ($success && empty($contact) && get_user_preferences('message_blocknoncontacts', NULL, $message['touserid']) == null) {
|
||||
// The user isn't a contact and they have selected to block non contacts so this message won't be sent.
|
||||
$success = false;
|
||||
$errormessage = get_string('userisblockingyounoncontact', 'message');
|
||||
}
|
||||
|
||||
//now we can send the message (at least try)
|
||||
if ($success) {
|
||||
//TODO: performance improvement - edit the function so we can pass an array instead one touser object
|
||||
$success = message_post_message($USER, $tousers[$message['touserid']], $text, FORMAT_MOODLE);
|
||||
}
|
||||
|
||||
//build the resultmsg
|
||||
if (isset($message['clientmsgid'])) {
|
||||
$resultmsg['clientmsgid'] = $message['clientmsgid'];
|
||||
}
|
||||
if ($success) {
|
||||
$resultmsg['msgid'] = $success;
|
||||
} else {
|
||||
$resultmsg['msgid'] = -1;
|
||||
$resultmsg['errormessage'] = $errormessage;
|
||||
}
|
||||
|
||||
$resultmessages[] = $resultmsg;
|
||||
}
|
||||
|
||||
return $resultmessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of method result value
|
||||
* @return external_description
|
||||
*/
|
||||
public static function send_messages_returns() {
|
||||
return new external_multiple_structure(
|
||||
new external_single_structure(
|
||||
array(
|
||||
'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
|
||||
'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds: id of the created message if it succeeded, -1 when failed'),
|
||||
'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
361
message/lib.php
361
message/lib.php
@ -53,6 +53,30 @@ define('MESSAGE_SEARCH_MAX_RESULTS', 200);
|
||||
define('MESSAGE_CONTACTS_PER_PAGE',10);
|
||||
define('MESSAGE_MAX_COURSE_NAME_LENGTH', 30);
|
||||
|
||||
/**
|
||||
* Define contants for messaging default settings population. For unambiguity of
|
||||
* plugin developer intentions we use 4-bit value (LSB numbering):
|
||||
* bit 0 - whether to send message when user is loggedin (MESSAGE_DEFAULT_LOGGEDIN)
|
||||
* bit 1 - whether to send message when user is loggedoff (MESSAGE_DEFAULT_LOGGEDOFF)
|
||||
* bit 2..3 - messaging permission (MESSAGE_DISALLOWED|MESSAGE_PERMITTED|MESSAGE_FORCED)
|
||||
*
|
||||
* MESSAGE_PERMITTED_MASK contains the mask we use to distinguish permission setting
|
||||
*/
|
||||
|
||||
define('MESSAGE_DEFAULT_LOGGEDIN', 0x01); // 0001
|
||||
define('MESSAGE_DEFAULT_LOGGEDOFF', 0x02); // 0010
|
||||
|
||||
define('MESSAGE_DISALLOWED', 0x04); // 0100
|
||||
define('MESSAGE_PERMITTED', 0x08); // 1000
|
||||
define('MESSAGE_FORCED', 0x0c); // 1100
|
||||
|
||||
define('MESSAGE_PERMITTED_MASK', 0x0c); // 1100
|
||||
|
||||
/**
|
||||
* Set default value for default outputs permitted setting
|
||||
*/
|
||||
define('MESSAGE_DEFAULT_PERMITTED', 'permitted');
|
||||
|
||||
if (!isset($CFG->message_contacts_refresh)) { // Refresh the contacts list every 60 seconds
|
||||
$CFG->message_contacts_refresh = 60;
|
||||
}
|
||||
@ -64,20 +88,21 @@ if (!isset($CFG->message_offline_time)) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the selector that allows the user to view their contacts, course participants, their recent
|
||||
* conversations etc
|
||||
* @param int $countunreadtotal how many unread messages does the user have?
|
||||
* @param int $viewing What is the user viewing? ie MESSAGE_VIEW_UNREAD_MESSAGES, MESSAGE_VIEW_SEARCH etc
|
||||
* @param object $user1 the user whose messages are being viewed
|
||||
* @param object $user2 the user $user1 is talking to
|
||||
* @param array $blockedusers an array of users blocked by $user1
|
||||
* @param array $onlinecontacts an array of $user1's online contacts
|
||||
* @param array $offlinecontacts an array of $user1's offline contacts
|
||||
* @param array $strangers an array of users who have messaged $user1 who aren't contacts
|
||||
* @param bool $showcontactactionlinks show action links (add/remove contact etc) next to the users in the contact selector
|
||||
* @param int $page if there are so many users listed that they have to be split into pages what page are we viewing
|
||||
* @return void
|
||||
*/
|
||||
* Print the selector that allows the user to view their contacts, course participants, their recent
|
||||
* conversations etc
|
||||
*
|
||||
* @param int $countunreadtotal how many unread messages does the user have?
|
||||
* @param int $viewing What is the user viewing? ie MESSAGE_VIEW_UNREAD_MESSAGES, MESSAGE_VIEW_SEARCH etc
|
||||
* @param object $user1 the user whose messages are being viewed
|
||||
* @param object $user2 the user $user1 is talking to
|
||||
* @param array $blockedusers an array of users blocked by $user1
|
||||
* @param array $onlinecontacts an array of $user1's online contacts
|
||||
* @param array $offlinecontacts an array of $user1's offline contacts
|
||||
* @param array $strangers an array of users who have messaged $user1 who aren't contacts
|
||||
* @param bool $showcontactactionlinks show action links (add/remove contact etc) next to the users in the contact selector
|
||||
* @param int $page if there are so many users listed that they have to be split into pages what page are we viewing
|
||||
* @return void
|
||||
*/
|
||||
function message_print_contact_selector($countunreadtotal, $viewing, $user1, $user2, $blockedusers, $onlinecontacts, $offlinecontacts, $strangers, $showcontactactionlinks, $page=0) {
|
||||
global $PAGE;
|
||||
|
||||
@ -140,16 +165,17 @@ function message_print_contact_selector($countunreadtotal, $viewing, $user1, $us
|
||||
}
|
||||
|
||||
/**
|
||||
* Print course participants. Called by message_print_contact_selector()
|
||||
* @param object $context the course context
|
||||
* @param int $courseid the course ID
|
||||
* @param string $contactselecturl the url to send the user to when a contact's name is clicked
|
||||
* @param bool $showactionlinks show action links (add/remove contact etc) next to the users
|
||||
* @param string $titletodisplay Optionally specify a title to display above the participants
|
||||
* @param int $page if there are so many users listed that they have to be split into pages what page are we viewing
|
||||
* @param object $user2 the user $user1 is talking to. They will be highlighted if they appear in the list of participants
|
||||
* @return void
|
||||
*/
|
||||
* Print course participants. Called by message_print_contact_selector()
|
||||
*
|
||||
* @param object $context the course context
|
||||
* @param int $courseid the course ID
|
||||
* @param string $contactselecturl the url to send the user to when a contact's name is clicked
|
||||
* @param bool $showactionlinks show action links (add/remove contact etc) next to the users
|
||||
* @param string $titletodisplay Optionally specify a title to display above the participants
|
||||
* @param int $page if there are so many users listed that they have to be split into pages what page are we viewing
|
||||
* @param object $user2 the user $user1 is talking to. They will be highlighted if they appear in the list of participants
|
||||
* @return void
|
||||
*/
|
||||
function message_print_participants($context, $courseid, $contactselecturl=null, $showactionlinks=true, $titletodisplay=null, $page=0, $user2=null) {
|
||||
global $DB, $USER, $PAGE, $OUTPUT;
|
||||
|
||||
@ -183,12 +209,13 @@ function message_print_participants($context, $courseid, $contactselecturl=null,
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve users blocked by $user1
|
||||
* @param object $user1 the user whose messages are being viewed
|
||||
* @param object $user2 the user $user1 is talking to. If they are being blocked
|
||||
* they will have a variable called 'isblocked' added to their user object
|
||||
* @return array the users blocked by $user1
|
||||
*/
|
||||
* Retrieve users blocked by $user1
|
||||
*
|
||||
* @param object $user1 the user whose messages are being viewed
|
||||
* @param object $user2 the user $user1 is talking to. If they are being blocked
|
||||
* they will have a variable called 'isblocked' added to their user object
|
||||
* @return array the users blocked by $user1
|
||||
*/
|
||||
function message_get_blocked_users($user1=null, $user2=null) {
|
||||
global $DB, $USER;
|
||||
|
||||
@ -225,14 +252,15 @@ function message_get_blocked_users($user1=null, $user2=null) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Print users blocked by $user1. Called by message_print_contact_selector()
|
||||
* @param array $blockedusers the users blocked by $user1
|
||||
* @param string $contactselecturl the url to send the user to when a contact's name is clicked
|
||||
* @param bool $showactionlinks show action links (add/remove contact etc) next to the users
|
||||
* @param string $titletodisplay Optionally specify a title to display above the participants
|
||||
* @param object $user2 the user $user1 is talking to. They will be highlighted if they appear in the list of blocked users
|
||||
* @return void
|
||||
*/
|
||||
* Print users blocked by $user1. Called by message_print_contact_selector()
|
||||
*
|
||||
* @param array $blockedusers the users blocked by $user1
|
||||
* @param string $contactselecturl the url to send the user to when a contact's name is clicked
|
||||
* @param bool $showactionlinks show action links (add/remove contact etc) next to the users
|
||||
* @param string $titletodisplay Optionally specify a title to display above the participants
|
||||
* @param object $user2 the user $user1 is talking to. They will be highlighted if they appear in the list of blocked users
|
||||
* @return void
|
||||
*/
|
||||
function message_print_blocked_users($blockedusers, $contactselecturl=null, $showactionlinks=true, $titletodisplay=null, $user2=null) {
|
||||
global $DB, $USER;
|
||||
|
||||
@ -262,12 +290,13 @@ function message_print_blocked_users($blockedusers, $contactselecturl=null, $sho
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve $user1's contacts (online, offline and strangers)
|
||||
* @param object $user1 the user whose messages are being viewed
|
||||
* @param object $user2 the user $user1 is talking to. If they are a contact
|
||||
* they will have a variable called 'iscontact' added to their user object
|
||||
* @return array containing 3 arrays. array($onlinecontacts, $offlinecontacts, $strangers)
|
||||
*/
|
||||
* Retrieve $user1's contacts (online, offline and strangers)
|
||||
*
|
||||
* @param object $user1 the user whose messages are being viewed
|
||||
* @param object $user2 the user $user1 is talking to. If they are a contact
|
||||
* they will have a variable called 'iscontact' added to their user object
|
||||
* @return array containing 3 arrays. array($onlinecontacts, $offlinecontacts, $strangers)
|
||||
*/
|
||||
function message_get_contacts($user1=null, $user2=null) {
|
||||
global $DB, $CFG, $USER;
|
||||
|
||||
@ -342,18 +371,19 @@ function message_get_contacts($user1=null, $user2=null) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Print $user1's contacts. Called by message_print_contact_selector()
|
||||
* @param array $onlinecontacts $user1's contacts which are online
|
||||
* @param array $offlinecontacts $user1's contacts which are offline
|
||||
* @param array $strangers users which are not contacts but who have messaged $user1
|
||||
* @param string $contactselecturl the url to send the user to when a contact's name is clicked
|
||||
* @param int $minmessages The minimum number of unread messages required from a user for them to be displayed
|
||||
* Typically 0 (show all contacts) or 1 (only show contacts from whom we have a new message)
|
||||
* @param bool $showactionlinks show action links (add/remove contact etc) next to the users
|
||||
* @param string $titletodisplay Optionally specify a title to display above the participants
|
||||
* @param object $user2 the user $user1 is talking to. They will be highlighted if they appear in the list of contacts
|
||||
* @return void
|
||||
*/
|
||||
* Print $user1's contacts. Called by message_print_contact_selector()
|
||||
*
|
||||
* @param array $onlinecontacts $user1's contacts which are online
|
||||
* @param array $offlinecontacts $user1's contacts which are offline
|
||||
* @param array $strangers users which are not contacts but who have messaged $user1
|
||||
* @param string $contactselecturl the url to send the user to when a contact's name is clicked
|
||||
* @param int $minmessages The minimum number of unread messages required from a user for them to be displayed
|
||||
* Typically 0 (show all contacts) or 1 (only show contacts from whom we have a new message)
|
||||
* @param bool $showactionlinks show action links (add/remove contact etc) next to the users
|
||||
* @param string $titletodisplay Optionally specify a title to display above the participants
|
||||
* @param object $user2 the user $user1 is talking to. They will be highlighted if they appear in the list of contacts
|
||||
* @return void
|
||||
*/
|
||||
function message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $contactselecturl=null, $minmessages=0, $showactionlinks=true, $titletodisplay=null, $user2=null) {
|
||||
global $CFG, $PAGE, $OUTPUT;
|
||||
|
||||
@ -426,16 +456,17 @@ function message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a select box allowing the user to choose to view new messages, course participants etc.
|
||||
* Called by message_print_contact_selector()
|
||||
* @param int $viewing What page is the user viewing ie MESSAGE_VIEW_UNREAD_MESSAGES, MESSAGE_VIEW_RECENT_CONVERSATIONS etc
|
||||
* @param array $courses array of course objects. The courses the user is enrolled in.
|
||||
* @param array $coursecontexts array of course contexts. Keyed on course id.
|
||||
* @param int $countunreadtotal how many unread messages does the user have?
|
||||
* @param int $countblocked how many users has the current user blocked?
|
||||
* @param string $strunreadmessages a preconstructed message about the number of unread messages the user has
|
||||
* @return void
|
||||
*/
|
||||
* Print a select box allowing the user to choose to view new messages, course participants etc.
|
||||
*
|
||||
* Called by message_print_contact_selector()
|
||||
* @param int $viewing What page is the user viewing ie MESSAGE_VIEW_UNREAD_MESSAGES, MESSAGE_VIEW_RECENT_CONVERSATIONS etc
|
||||
* @param array $courses array of course objects. The courses the user is enrolled in.
|
||||
* @param array $coursecontexts array of course contexts. Keyed on course id.
|
||||
* @param int $countunreadtotal how many unread messages does the user have?
|
||||
* @param int $countblocked how many users has the current user blocked?
|
||||
* @param string $strunreadmessages a preconstructed message about the number of unread messages the user has
|
||||
* @return void
|
||||
*/
|
||||
function message_print_usergroup_selector($viewing, $courses, $coursecontexts, $countunreadtotal, $countblocked, $strunreadmessages) {
|
||||
$options = array();
|
||||
$textlib = textlib_get_instance(); // going to use textlib services
|
||||
@ -482,10 +513,11 @@ function message_print_usergroup_selector($viewing, $courses, $coursecontexts, $
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the course contexts for all of the users courses
|
||||
* @param array $courses array of course objects. The courses the user is enrolled in.
|
||||
* @return array of course contexts
|
||||
*/
|
||||
* Load the course contexts for all of the users courses
|
||||
*
|
||||
* @param array $courses array of course objects. The courses the user is enrolled in.
|
||||
* @return array of course contexts
|
||||
*/
|
||||
function message_get_course_contexts($courses) {
|
||||
$coursecontexts = array();
|
||||
|
||||
@ -498,6 +530,7 @@ function message_get_course_contexts($courses) {
|
||||
|
||||
/**
|
||||
* strip off action parameters like 'removecontact'
|
||||
*
|
||||
* @param moodle_url/string $moodleurl a URL. Typically the current page URL.
|
||||
* @return string the URL minus parameters that perform actions (like adding/removing/blocking a contact).
|
||||
*/
|
||||
@ -511,6 +544,7 @@ function message_remove_url_params($moodleurl) {
|
||||
* Count the number of messages with a field having a specified value.
|
||||
* if $field is empty then return count of the whole array
|
||||
* if $field is non-existent then return 0
|
||||
*
|
||||
* @param array $messagearray array of message objects
|
||||
* @param string $field the field to inspect on the message objects
|
||||
* @param string $value the value to test the field against
|
||||
@ -528,6 +562,7 @@ function message_count_messages($messagearray, $field='', $value='') {
|
||||
|
||||
/**
|
||||
* Returns the count of unread messages for user. Either from a specific user or from all users.
|
||||
*
|
||||
* @param object $user1 the first user. Defaults to $USER
|
||||
* @param object $user2 the second user. If null this function will count all of user 1's unread messages.
|
||||
* @return int the count of $user1's unread messages
|
||||
@ -550,7 +585,9 @@ function message_count_unread_messages($user1=null, $user2=null) {
|
||||
|
||||
/**
|
||||
* Count the number of users blocked by $user1
|
||||
* @param $user1
|
||||
*
|
||||
* @param object $user1 user object
|
||||
* @return int the number of blocked users
|
||||
*/
|
||||
function message_count_blocked_users($user1=null) {
|
||||
global $USER, $DB;
|
||||
@ -569,6 +606,7 @@ function message_count_blocked_users($user1=null) {
|
||||
|
||||
/**
|
||||
* Print the search form and search results if a search has been performed
|
||||
*
|
||||
* @param boolean $advancedsearch show basic or advanced search form
|
||||
* @param object $user1 the current user
|
||||
* @return boolean true if a search was performed
|
||||
@ -627,6 +665,7 @@ function message_print_search($advancedsearch = false, $user1=null) {
|
||||
/**
|
||||
* Get the users recent conversations meaning all the people they've recently
|
||||
* sent or received a message from plus the most recent message sent to or received from each other user
|
||||
*
|
||||
* @param object $user the current user
|
||||
* @param int $limitfrom can be used for paging
|
||||
* @param int $limitto can be used for paging
|
||||
@ -718,6 +757,7 @@ function message_get_recent_conversations($user, $limitfrom=0, $limitto=100) {
|
||||
|
||||
/**
|
||||
* Sort function used to order conversations
|
||||
*
|
||||
* @param object $a A conversation object
|
||||
* @param object $b A conversation object
|
||||
* @return integer
|
||||
@ -732,6 +772,7 @@ function conversationsort($a, $b)
|
||||
|
||||
/**
|
||||
* Get the users recent event notifications
|
||||
*
|
||||
* @param object $user the current user
|
||||
* @param int $limitfrom can be used for paging
|
||||
* @param int $limitto can be used for paging
|
||||
@ -754,8 +795,10 @@ function message_get_recent_notifications($user, $limitfrom=0, $limitto=100) {
|
||||
|
||||
/**
|
||||
* Print the user's recent conversations
|
||||
*
|
||||
* @param object $user1 the current user
|
||||
* @param bool $showicontext flag indicating whether or not to show text next to the action icons
|
||||
* @return void
|
||||
*/
|
||||
function message_print_recent_conversations($user=null, $showicontext=false) {
|
||||
global $USER;
|
||||
@ -776,7 +819,9 @@ function message_print_recent_conversations($user=null, $showicontext=false) {
|
||||
|
||||
/**
|
||||
* Print the user's recent notifications
|
||||
*
|
||||
* @param object $user1 the current user
|
||||
* @return void
|
||||
*/
|
||||
function message_print_recent_notifications($user=null) {
|
||||
global $USER;
|
||||
@ -798,11 +843,13 @@ function message_print_recent_notifications($user=null) {
|
||||
|
||||
/**
|
||||
* Print a list of recent messages
|
||||
*
|
||||
* @staticvar type $dateformat
|
||||
* @param array $messages the messages to display
|
||||
* @param object $user the current user
|
||||
* @param bool $showotheruser display information on the other user?
|
||||
* @param bool $showicontext show text next to the action icons?
|
||||
* @return void
|
||||
*/
|
||||
function message_print_recent_messages_table($messages, $user=null, $showotheruser=true, $showicontext=false) {
|
||||
global $OUTPUT;
|
||||
@ -871,6 +918,7 @@ function message_print_recent_messages_table($messages, $user=null, $showotherus
|
||||
|
||||
/**
|
||||
* Add the selected user as a contact for the current user
|
||||
*
|
||||
* @param int $contactid the ID of the user to add as a contact
|
||||
* @param int $blocked 1 if you wish to block the contact
|
||||
* @return bool/int false if the $contactid isnt a valid user id. True if no changes made.
|
||||
@ -907,6 +955,7 @@ function message_add_contact($contactid, $blocked=0) {
|
||||
|
||||
/**
|
||||
* remove a contact
|
||||
*
|
||||
* @param type $contactid the user ID of the contact to remove
|
||||
* @return bool returns the result of delete_records()
|
||||
*/
|
||||
@ -917,6 +966,7 @@ function message_remove_contact($contactid) {
|
||||
|
||||
/**
|
||||
* Unblock a contact. Note that this reverts the previously blocked user back to a non-contact.
|
||||
*
|
||||
* @param int $contactid the user ID of the contact to unblock
|
||||
* @return bool returns the result of delete_records()
|
||||
*/
|
||||
@ -927,6 +977,7 @@ function message_unblock_contact($contactid) {
|
||||
|
||||
/**
|
||||
* block a user
|
||||
*
|
||||
* @param int $contactid the user ID of the user to block
|
||||
*/
|
||||
function message_block_contact($contactid) {
|
||||
@ -935,7 +986,9 @@ function message_block_contact($contactid) {
|
||||
|
||||
/**
|
||||
* Load a user's contact record
|
||||
*
|
||||
* @param int $contactid the user ID of the user whose contact record you want
|
||||
* @return array message contacts
|
||||
*/
|
||||
function message_get_contact($contactid) {
|
||||
global $USER, $DB;
|
||||
@ -944,9 +997,11 @@ function message_get_contact($contactid) {
|
||||
|
||||
/**
|
||||
* Print the results of a message search
|
||||
*
|
||||
* @param mixed $frm submitted form data
|
||||
* @param bool $showicontext show text next to action icons?
|
||||
* @param object $user1 the current user
|
||||
* @return void
|
||||
*/
|
||||
function message_print_search_results($frm, $showicontext=false, $user1=null) {
|
||||
global $USER, $DB, $OUTPUT;
|
||||
@ -1212,10 +1267,12 @@ function message_print_search_results($frm, $showicontext=false, $user1=null) {
|
||||
|
||||
/**
|
||||
* Print information on a user. Used when printing search results.
|
||||
*
|
||||
* @param object/bool $user the user to display or false if you just want $USER
|
||||
* @param bool $iscontact is the user being displayed a contact?
|
||||
* @param bool $isblocked is the user being displayed blocked?
|
||||
* @param bool $includeicontext include text next to the action icons?
|
||||
* @return void
|
||||
*/
|
||||
function message_print_user ($user=false, $iscontact=false, $isblocked=false, $includeicontext=false) {
|
||||
global $USER, $OUTPUT;
|
||||
@ -1259,6 +1316,7 @@ function message_print_user ($user=false, $iscontact=false, $isblocked=false, $i
|
||||
|
||||
/**
|
||||
* Print a message contact link
|
||||
*
|
||||
* @staticvar type $str
|
||||
* @param int $userid the ID of the user to apply to action to
|
||||
* @param string $linktype can be add, remove, block or unblock
|
||||
@ -1333,6 +1391,7 @@ function message_contact_link($userid, $linktype='add', $return=false, $script=n
|
||||
|
||||
/**
|
||||
* echo or return a link to take the user to the full message history between themselves and another user
|
||||
*
|
||||
* @staticvar type $strmessagehistory
|
||||
* @param int $userid1 the ID of the current user
|
||||
* @param int $userid2 the ID of the other user
|
||||
@ -1456,6 +1515,7 @@ function message_search_users($courseid, $searchtext, $sort='', $exceptions='')
|
||||
|
||||
/**
|
||||
* search a user's messages
|
||||
*
|
||||
* @param array $searchterms an array of search terms (strings)
|
||||
* @param bool $fromme include messages from the user?
|
||||
* @param bool $tome include messages to the user?
|
||||
@ -1597,6 +1657,7 @@ function message_search($searchterms, $fromme=true, $tome=true, $courseid='none'
|
||||
* Given a message object that we already know has a long message
|
||||
* this function truncates the message nicely to the first
|
||||
* sane place between $CFG->forum_longpost and $CFG->forum_shortpost
|
||||
*
|
||||
* @param string $message the message
|
||||
* @param int $minlength the minimum length to trim the message to
|
||||
* @return string the shortened message
|
||||
@ -1652,6 +1713,7 @@ function message_shorten_message($message, $minlength = 0) {
|
||||
* Given a string and an array of keywords, this function looks
|
||||
* for the first keyword in the string, and then chops out a
|
||||
* small section from the text that shows that word in context.
|
||||
*
|
||||
* @param string $message the text to search
|
||||
* @param array $keywords array of keywords to find
|
||||
*/
|
||||
@ -1699,6 +1761,7 @@ function message_get_fragment($message, $keywords) {
|
||||
|
||||
/**
|
||||
* Retrieve the messages between two users
|
||||
*
|
||||
* @param object $user1 the current user
|
||||
* @param object $user2 the other user
|
||||
* @param int $limitnum the maximum number of messages to retrieve
|
||||
@ -1754,6 +1817,7 @@ function message_get_history($user1, $user2, $limitnum=0, $viewingnewmessages=fa
|
||||
|
||||
/**
|
||||
* Print the message history between two users
|
||||
*
|
||||
* @param object $user1 the current user
|
||||
* @param object $user2 the other user
|
||||
* @param string $search search terms to highlight
|
||||
@ -1853,6 +1917,7 @@ function message_print_message_history($user1,$user2,$search='',$messagelimit=0,
|
||||
|
||||
/**
|
||||
* Format a message for display in the message history
|
||||
*
|
||||
* @param object $message the message object
|
||||
* @param string $format optional date format
|
||||
* @param string $keywords keywords to highlight
|
||||
@ -1893,6 +1958,7 @@ function message_format_message($message, $format='', $keywords='', $class='othe
|
||||
|
||||
/**
|
||||
* Format a the context url and context url name of a message for display
|
||||
*
|
||||
* @param object $message the message object
|
||||
* @return string the formatted string
|
||||
*/
|
||||
@ -1916,6 +1982,7 @@ function message_format_contexturl($message) {
|
||||
|
||||
/**
|
||||
* Send a message from one user to another. Will be delivered according to the message recipients messaging preferences
|
||||
*
|
||||
* @param object $userfrom the message sender
|
||||
* @param object $userto the message recipient
|
||||
* @param string $message the message
|
||||
@ -1968,6 +2035,7 @@ function message_post_message($userfrom, $userto, $message, $format) {
|
||||
* on large datasets?
|
||||
*
|
||||
* @todo: deprecated - to be deleted in 2.2
|
||||
* @return array
|
||||
*/
|
||||
function message_get_participants() {
|
||||
global $CFG, $DB;
|
||||
@ -1983,12 +2051,14 @@ function message_get_participants() {
|
||||
/**
|
||||
* Print a row of contactlist displaying user picture, messages waiting and
|
||||
* block links etc
|
||||
*
|
||||
* @param object $contact contact object containing all fields required for $OUTPUT->user_picture()
|
||||
* @param bool $incontactlist is the user a contact of ours?
|
||||
* @param bool $isblocked is the user blocked?
|
||||
* @param string $selectcontacturl the url to send the user to when a contact's name is clicked
|
||||
* @param bool $showactionlinks display action links next to the other users (add contact, block user etc)
|
||||
* @param object $selecteduser the user the current user is viewing (if any). They will be highlighted.
|
||||
* @return void
|
||||
*/
|
||||
function message_print_contactlist_user($contact, $incontactlist = true, $isblocked = false, $selectcontacturl = null, $showactionlinks = true, $selecteduser=null) {
|
||||
global $OUTPUT, $USER;
|
||||
@ -2048,6 +2118,7 @@ function message_print_contactlist_user($contact, $incontactlist = true, $isbloc
|
||||
|
||||
/**
|
||||
* Constructs the add/remove contact link to display next to other users
|
||||
*
|
||||
* @param bool $incontactlist is the user a contact
|
||||
* @param bool $isblocked is the user blocked
|
||||
* @param type $contact contact object
|
||||
@ -2072,6 +2143,7 @@ function message_get_contact_add_remove_link($incontactlist, $isblocked, $contac
|
||||
|
||||
/**
|
||||
* Constructs the block contact link to display next to other users
|
||||
*
|
||||
* @param bool $incontactlist is the user a contact
|
||||
* @param bool $isblocked is the user blocked
|
||||
* @param type $contact contact object
|
||||
@ -2096,9 +2168,10 @@ function message_get_contact_block_link($incontactlist, $isblocked, $contact, $s
|
||||
return $strblock;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Moves messages from a particular user from the message table (unread messages) to message_read
|
||||
* This is typically only used when a user is deleted
|
||||
*
|
||||
* @param object $userid User id
|
||||
* @return boolean success
|
||||
*/
|
||||
@ -2115,11 +2188,12 @@ function message_move_userfrom_unread2read($userid) {
|
||||
}
|
||||
|
||||
/**
|
||||
* marks ALL messages being sent from $fromuserid to $touserid as read
|
||||
* @param int $touserid the id of the message recipient
|
||||
* @param int $fromuserid the id of the message sender
|
||||
* @return void
|
||||
*/
|
||||
* marks ALL messages being sent from $fromuserid to $touserid as read
|
||||
*
|
||||
* @param int $touserid the id of the message recipient
|
||||
* @param int $fromuserid the id of the message sender
|
||||
* @return void
|
||||
*/
|
||||
function message_mark_messages_read($touserid, $fromuserid){
|
||||
global $DB;
|
||||
|
||||
@ -2134,12 +2208,13 @@ function message_mark_messages_read($touserid, $fromuserid){
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a single message as read
|
||||
* @param message an object with an object property ie $message->id which is an id in the message table
|
||||
* @param int $timeread the timestamp for when the message should be marked read. Usually time().
|
||||
* @param bool $messageworkingempty Is the message_working table already confirmed empty for this message?
|
||||
* @return int the ID of the message in the message_read table
|
||||
*/
|
||||
* Mark a single message as read
|
||||
*
|
||||
* @param message an object with an object property ie $message->id which is an id in the message table
|
||||
* @param int $timeread the timestamp for when the message should be marked read. Usually time().
|
||||
* @param bool $messageworkingempty Is the message_working table already confirmed empty for this message?
|
||||
* @return int the ID of the message in the message_read table
|
||||
*/
|
||||
function message_mark_message_read($message, $timeread, $messageworkingempty=false) {
|
||||
global $DB;
|
||||
|
||||
@ -2159,11 +2234,131 @@ function message_mark_message_read($message, $timeread, $messageworkingempty=fal
|
||||
|
||||
/**
|
||||
* A helper function that prints a formatted heading
|
||||
*
|
||||
* @param string $title the heading to display
|
||||
* @param int $colspan
|
||||
* @return void
|
||||
*/
|
||||
function message_print_heading($title, $colspan=3) {
|
||||
echo html_writer::start_tag('tr');
|
||||
echo html_writer::tag('td', $title, array('colspan' => $colspan, 'class' => 'heading'));
|
||||
echo html_writer::end_tag('tr');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all message processors, validate corresponding plugin existance and
|
||||
* system configuration
|
||||
*
|
||||
* @param bool $ready only return ready-to-use processors
|
||||
* @return mixed $processors array of objects containing information on message processors
|
||||
*/
|
||||
function get_message_processors($ready = false) {
|
||||
global $DB, $CFG;
|
||||
|
||||
static $processors;
|
||||
|
||||
if (empty($processors)) {
|
||||
// Get all processors, ensure the name column is the first so it will be the array key
|
||||
$processors = $DB->get_records('message_processors', null, 'name DESC', 'name, id, enabled');
|
||||
foreach ($processors as &$processor){
|
||||
$processorfile = $CFG->dirroot. '/message/output/'.$processor->name.'/message_output_'.$processor->name.'.php';
|
||||
if (is_readable($processorfile)) {
|
||||
include_once($processorfile);
|
||||
$processclass = 'message_output_' . $processor->name;
|
||||
if (class_exists($processclass)) {
|
||||
$pclass = new $processclass();
|
||||
$processor->object = $pclass;
|
||||
$processor->configured = 0;
|
||||
if ($pclass->is_system_configured()) {
|
||||
$processor->configured = 1;
|
||||
}
|
||||
$processor->hassettings = 0;
|
||||
if (is_readable($CFG->dirroot.'/message/output/'.$processor->name.'/settings.php')) {
|
||||
$processor->hassettings = 1;
|
||||
}
|
||||
$processor->available = 1;
|
||||
} else {
|
||||
print_error('errorcallingprocessor', 'message');
|
||||
}
|
||||
} else {
|
||||
$processor->available = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($ready) {
|
||||
// Filter out enabled and system_configured processors
|
||||
$readyprocessors = $processors;
|
||||
foreach ($readyprocessors as $readyprocessor) {
|
||||
if (!($readyprocessor->enabled && $readyprocessor->configured)) {
|
||||
unset($readyprocessors[$readyprocessor->name]);
|
||||
}
|
||||
}
|
||||
return $readyprocessors;
|
||||
}
|
||||
|
||||
return $processors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get messaging outputs default (site) preferences
|
||||
*
|
||||
* @return object $processors object containing information on message processors
|
||||
*/
|
||||
function get_message_output_default_preferences() {
|
||||
$preferences = get_config('message');
|
||||
if (!$preferences) {
|
||||
$preferences = new stdClass();
|
||||
}
|
||||
return $preferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate message default settings from binary value to the array of string
|
||||
* representing the settings to be stored. Also validate the provided value and
|
||||
* use default if it is malformed.
|
||||
*
|
||||
* @param int $plugindefault Default setting suggested by plugin
|
||||
* @param string $processorname The name of processor
|
||||
* @return array $settings array of strings in the order: $permitted, $loggedin, $loggedoff.
|
||||
*/
|
||||
function translate_message_default_setting($plugindefault, $processorname) {
|
||||
// Preset translation arrays
|
||||
$permittedvalues = array(
|
||||
0x04 => 'disallowed',
|
||||
0x08 => 'permitted',
|
||||
0x0c => 'forced',
|
||||
);
|
||||
|
||||
$loggedinstatusvalues = array(
|
||||
0x00 => null, // use null if loggedin/loggedoff is not defined
|
||||
0x01 => 'loggedin',
|
||||
0x02 => 'loggedoff',
|
||||
);
|
||||
|
||||
// define the default setting
|
||||
if ($processorname == 'email') {
|
||||
$default = MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF;
|
||||
} else {
|
||||
$default = MESSAGE_PERMITTED;
|
||||
}
|
||||
|
||||
// Validate the value. It should not exceed the maximum size
|
||||
if (!is_int($plugindefault) || ($plugindefault > 0x0f)) {
|
||||
$OUTPUT->notification(get_string('errortranslatingdefault', 'message'), 'notifyproblem');
|
||||
$plugindefault = $default;
|
||||
}
|
||||
// Use plugin default setting of 'permitted' is 0
|
||||
if (!($plugindefault & MESSAGE_PERMITTED_MASK)) {
|
||||
$plugindefault = $default;
|
||||
}
|
||||
|
||||
$permitted = $permittedvalues[$plugindefault & MESSAGE_PERMITTED_MASK];
|
||||
$loggedin = $loggedoff = null;
|
||||
|
||||
if (($plugindefault & MESSAGE_PERMITTED_MASK) == MESSAGE_PERMITTED) {
|
||||
$loggedin = $loggedinstatusvalues[$plugindefault & MESSAGE_DEFAULT_LOGGEDIN];
|
||||
$loggedoff = $loggedinstatusvalues[$plugindefault & MESSAGE_DEFAULT_LOGGEDOFF];
|
||||
}
|
||||
|
||||
return array($permitted, $loggedin, $loggedoff);
|
||||
}
|
||||
|
@ -43,3 +43,48 @@ M.core_message.init_notification = function(Y, title, content, url) {
|
||||
}, o);
|
||||
});
|
||||
};
|
||||
|
||||
M.core_message.init_defaultoutputs = function(Y) {
|
||||
var defaultoutputs = {
|
||||
|
||||
init : function() {
|
||||
Y.all('#defaultmessageoutputs select').each(function(node) {
|
||||
// attach event listener
|
||||
node.on('change', defaultoutputs.changeState);
|
||||
// set initial layout
|
||||
node.simulate("change");
|
||||
}, this);
|
||||
},
|
||||
|
||||
changeState : function(e) {
|
||||
var value = e.target._node.options[e.target.get('selectedIndex')].value;
|
||||
var parentnode = e.target.ancestor('td');
|
||||
switch (value) {
|
||||
case 'forced':
|
||||
defaultoutputs.updateCheckboxes(parentnode, 1, 1);
|
||||
break;
|
||||
case 'disallowed':
|
||||
defaultoutputs.updateCheckboxes(parentnode, 1, 0);
|
||||
break;
|
||||
case 'permitted':
|
||||
defaultoutputs.updateCheckboxes(parentnode, 0, 0);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
updateCheckboxes : function(blocknode, disabled, checked) {
|
||||
blocknode.all('input[type=checkbox]').each(function(node) {
|
||||
node.removeAttribute('disabled');
|
||||
if (disabled) {
|
||||
node.setAttribute('disabled', 1)
|
||||
node.removeAttribute('checked');
|
||||
}
|
||||
if (checked) {
|
||||
node.setAttribute('checked', 1)
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
|
||||
defaultoutputs.init();
|
||||
}
|
@ -23,5 +23,20 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['pluginname'] = 'Email';
|
||||
$string['allowusermailcharset'] = 'Allow user to select character set';
|
||||
$string['configallowusermailcharset'] = 'Enabling this, every user in the site will be able to specify his own charset for email.';
|
||||
$string['configmailnewline'] = 'Newline characters used in mail messages. CRLF is required according to RFC 822bis, some mail servers do automatic conversion from LF to CRLF, other mail servers do incorrect conversion from CRLF to CRCRLF, yet others reject mails with bare LF (qmail for example). Try changing this setting if you are having problems with undelivered emails or double newlines.';
|
||||
$string['confignoreplyaddress'] = 'Emails are sometimes sent out on behalf of a user (eg forum posts). The email address you specify here will be used as the "From" address in those cases when the recipients should not be able to reply directly to the user (eg when a user chooses to keep their address private).';
|
||||
$string['configsitemailcharset'] = 'All the emails generated by your site will be sent in the charset specified here. Anyway, every individual user will be able to adjust it if the next setting is enabled.';
|
||||
$string['configsmtphosts'] = 'Give the full name of one or more local SMTP servers that Moodle should use to send mail (eg \'mail.a.com\' or \'mail.a.com;mail.b.com\'). To specify a non-default port (i.e other than port 25), you can use the [server]:[port] syntax (eg \'mail.a.com:587\'. If you leave it blank, Moodle will use the PHP default method of sending mail.';
|
||||
$string['configsmtpmaxbulk'] = 'Maximum number of messages sent per SMTP session. Grouping messages may speed up the sending of emails. Values lower than 2 force creation of new SMTP session for each email.';
|
||||
$string['configsmtpuser'] = 'If you have specified an SMTP server above, and the server requires authentication, then enter the username and password here.';
|
||||
$string['email'] = 'Send email notifications to';
|
||||
$string['mailnewline'] = 'Newline characters in mail';
|
||||
$string['noreplyaddress'] = 'No-reply address';
|
||||
$string['pluginname'] = 'Email';
|
||||
$string['sitemailcharset'] = 'Character set';
|
||||
$string['smtphosts'] = 'SMTP hosts';
|
||||
$string['smtpmaxbulk'] = 'SMTP session limit';
|
||||
$string['smtppass'] = 'SMTP password';
|
||||
$string['smtpuser'] = 'SMTP username';
|
||||
|
@ -83,7 +83,7 @@ class message_output_email extends message_output {
|
||||
* @param array $preferences preferences array
|
||||
*/
|
||||
function process_form($form, &$preferences){
|
||||
if (isset($form->email_email)) {
|
||||
if (isset($form->email_email) && !empty($form->email_email)) {
|
||||
$preferences['message_processor_email_email'] = $form->email_email;
|
||||
}
|
||||
}
|
||||
|
44
message/output/email/settings.php
Normal file
44
message/output/email/settings.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Email configuration page
|
||||
*
|
||||
* @package message
|
||||
* @subpackage email
|
||||
* @copyright 2011 Lancaster University Network Services Limited
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
if ($ADMIN->fulltree) {
|
||||
$settings->add(new admin_setting_configtext('smtphosts', get_string('smtphosts', 'message_email'), get_string('configsmtphosts', 'message_email'), '', PARAM_RAW));
|
||||
$settings->add(new admin_setting_configtext('smtpuser', get_string('smtpuser', 'message_email'), get_string('configsmtpuser', 'message_email'), '', PARAM_NOTAGS));
|
||||
$settings->add(new admin_setting_configpasswordunmask('smtppass', get_string('smtppass', 'message_email'), get_string('configsmtpuser', 'message_email'), ''));
|
||||
$settings->add(new admin_setting_configtext('smtpmaxbulk', get_string('smtpmaxbulk', 'message_email'), get_string('configsmtpmaxbulk', 'message_email'), 1, PARAM_INT));
|
||||
$settings->add(new admin_setting_configtext('noreplyaddress', get_string('noreplyaddress', 'message_email'), get_string('confignoreplyaddress', 'message_email'), 'noreply@' . get_host_from_url($CFG->wwwroot), PARAM_NOTAGS));
|
||||
|
||||
$charsets = get_list_of_charsets();
|
||||
unset($charsets['UTF-8']); // not needed here
|
||||
$options = array();
|
||||
$options['0'] = 'UTF-8';
|
||||
$options = array_merge($options, $charsets);
|
||||
$settings->add(new admin_setting_configselect('sitemailcharset', get_string('sitemailcharset', 'message_email'), get_string('configsitemailcharset','message_email'), '0', $options));
|
||||
$settings->add(new admin_setting_configcheckbox('allowusermailcharset', get_string('allowusermailcharset', 'message_email'), get_string('configallowusermailcharset', 'message_email'), 0));
|
||||
$options = array('LF'=>'LF', 'CRLF'=>'CRLF');
|
||||
$settings->add(new admin_setting_configselect('mailnewline', get_string('mailnewline', 'message_email'), get_string('configmailnewline','message_email'), 'LF', $options));
|
||||
}
|
@ -23,6 +23,16 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['pluginname'] = 'Jabber message';
|
||||
$string['configjabberhost'] = 'The server to connect to to send jabber message notifications';
|
||||
$string['configjabberserver'] = 'XMPP host ID (can be left empty if the same as Jabber host)';
|
||||
$string['configjabberusername'] = 'The user name to use when connecting to the Jabber server';
|
||||
$string['configjabberpassword'] = 'The password to use when connecting to the Jabber server';
|
||||
$string['configjabberport'] = 'The port to use when connecting to the Jabber server';
|
||||
$string['jabberhost'] = 'Jabber host';
|
||||
$string['jabberid'] = 'Jabber ID';
|
||||
$string['jabberserver'] = 'Jabber server';
|
||||
$string['jabberusername'] = 'Jabber user name';
|
||||
$string['jabberpassword'] = 'Jabber password';
|
||||
$string['jabberport'] = 'Jabber port';
|
||||
$string['notconfigured'] = 'The Jabber server hasn\'t been configured so Jabber messages cannot be sent';
|
||||
$string['pluginname'] = 'Jabber message';
|
||||
|
@ -44,7 +44,6 @@ class message_output_jabber extends message_output {
|
||||
function send_message($eventdata){
|
||||
global $CFG;
|
||||
|
||||
if (message_output_jabber::_jabber_configured()) {
|
||||
if (!empty($CFG->noemailever)) {
|
||||
// hidden setting for development sites, set in config.php if needed
|
||||
debugging('$CFG->noemailever active, no jabber message sent.', DEBUG_MINIMAL);
|
||||
@ -55,7 +54,7 @@ class message_output_jabber extends message_output {
|
||||
static $jabberaddresses = array();
|
||||
|
||||
if (!array_key_exists($eventdata->userto->id, $jabberaddresses)) {
|
||||
$jabberaddresses[$eventdata->userto->id] = get_user_preferences('message_processor_jabber_jabberid', $eventdata->userto->email, $eventdata->userto->id);
|
||||
$jabberaddresses[$eventdata->userto->id] = get_user_preferences('message_processor_jabber_jabberid', null, $eventdata->userto->id);
|
||||
}
|
||||
$jabberaddress = $jabberaddresses[$eventdata->userto->id];
|
||||
|
||||
@ -81,9 +80,6 @@ class message_output_jabber extends message_output {
|
||||
debugging($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//note that we're reporting success if message was sent or if Jabber simply isnt configured
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -94,7 +90,7 @@ class message_output_jabber extends message_output {
|
||||
function config_form($preferences){
|
||||
global $CFG;
|
||||
|
||||
if (!message_output_jabber::_jabber_configured()) {
|
||||
if (!$this->is_system_configured()) {
|
||||
return get_string('notconfigured','message_jabber');
|
||||
} else {
|
||||
return get_string('jabberid', 'message_jabber').': <input size="30" name="jabber_jabberid" value="'.$preferences->jabber_jabberid.'" />';
|
||||
@ -107,7 +103,7 @@ class message_output_jabber extends message_output {
|
||||
* @param array $preferences preferences array
|
||||
*/
|
||||
function process_form($form, &$preferences){
|
||||
if (isset($form->jabber_jabberid)) {
|
||||
if (isset($form->jabber_jabberid) && !empty($form->jabber_jabberid)) {
|
||||
$preferences['message_processor_jabber_jabberid'] = $form->jabber_jabberid;
|
||||
}
|
||||
}
|
||||
@ -125,11 +121,25 @@ class message_output_jabber extends message_output {
|
||||
* Tests whether the Jabber settings have been configured
|
||||
* @return boolean true if Jabber is configured
|
||||
*/
|
||||
private function _jabber_configured() {
|
||||
function is_system_configured() {
|
||||
global $CFG;
|
||||
return (!empty($CFG->jabberhost) && !empty($CFG->jabberport) && !empty($CFG->jabberusername) && !empty($CFG->jabberpassword));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the Jabber settings have been configured on user level
|
||||
* @param object $user the user object, defaults to $USER.
|
||||
* @return bool has the user made all the necessary settings
|
||||
* in their profile to allow this plugin to be used.
|
||||
*/
|
||||
function is_user_configured($user = null) {
|
||||
global $USER;
|
||||
|
||||
if (is_null($user)) {
|
||||
$user = $USER;
|
||||
}
|
||||
return (bool)get_user_preferences('message_processor_jabber_jabberid', null, $user->id);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
34
message/output/jabber/settings.php
Normal file
34
message/output/jabber/settings.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Jabber configuration page
|
||||
*
|
||||
* @package message
|
||||
* @subpackage jabber
|
||||
* @copyright 2011 Lancaster University Network Services Limited
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
if ($ADMIN->fulltree) {
|
||||
$settings->add(new admin_setting_configtext('jabberhost', get_string('jabberhost', 'message_jabber'), get_string('configjabberhost', 'message_jabber'), '', PARAM_RAW));
|
||||
$settings->add(new admin_setting_configtext('jabberserver', get_string('jabberserver', 'message_jabber'), get_string('configjabberserver', 'message_jabber'), '', PARAM_RAW));
|
||||
$settings->add(new admin_setting_configtext('jabberusername', get_string('jabberusername', 'message_jabber'), get_string('configjabberusername', 'message_jabber'), '', PARAM_RAW));
|
||||
$settings->add(new admin_setting_configpasswordunmask('jabberpassword', get_string('jabberpassword', 'message_jabber'), get_string('configjabberpassword', 'message_jabber'), ''));
|
||||
$settings->add(new admin_setting_configtext('jabberport', get_string('jabberport', 'message_jabber'), get_string('configjabberport', 'message_jabber'), 5222, PARAM_INT));
|
||||
}
|
@ -39,6 +39,22 @@ abstract class message_output {
|
||||
public abstract function process_form($form, &$preferences);
|
||||
public abstract function load_data(&$preferences, $userid);
|
||||
public abstract function config_form($preferences);
|
||||
/**
|
||||
* @return bool have all the necessary config settings been
|
||||
* made that allow this plugin to be used.
|
||||
*/
|
||||
public function is_system_configured() {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* @param object $user the user object, defaults to $USER.
|
||||
* @return bool has the user made all the necessary settings
|
||||
* in their profile to allow this plugin to be used.
|
||||
*/
|
||||
public function is_user_configured($user = null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
346
message/renderer.php
Normal file
346
message/renderer.php
Normal file
@ -0,0 +1,346 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Messaging libraries
|
||||
*
|
||||
* @package message
|
||||
* @copyright 2011 Lancaster University Network Services Limited
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* message Renderer
|
||||
*
|
||||
* Class for rendering various message objects
|
||||
*
|
||||
* @package message
|
||||
* @copyright 2011 Lancaster University Network Services Limited
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_message_renderer extends plugin_renderer_base {
|
||||
|
||||
/**
|
||||
* Display the interface to manage message outputs
|
||||
*
|
||||
* @param mixed $processors array of objects containing message processors
|
||||
* @return string The text to render
|
||||
*/
|
||||
public function manage_messageoutputs($processors) {
|
||||
global $CFG;
|
||||
// Display the current workflows
|
||||
$table = new html_table();
|
||||
$table->attributes['class'] = 'generaltable';
|
||||
$table->data = array();
|
||||
$table->head = array(
|
||||
get_string('name'),
|
||||
get_string('enable'),
|
||||
get_string('settings'),
|
||||
);
|
||||
$table->colclasses = array(
|
||||
'displayname', 'availability', 'settings',
|
||||
);
|
||||
|
||||
foreach ($processors as $processor) {
|
||||
$row = new html_table_row();
|
||||
$row->attributes['class'] = 'messageoutputs';
|
||||
|
||||
// Name
|
||||
$name = new html_table_cell($processor->name);
|
||||
|
||||
// Enable
|
||||
$enable = new html_table_cell();
|
||||
$enable->attributes['class'] = 'mdl-align';
|
||||
if (!$processor->available) {
|
||||
$enable->text = html_writer::nonempty_tag('span', get_string('outputnotavailable', 'message'), array('class' => 'error'));
|
||||
} else if (!$processor->configured) {
|
||||
$enable->text = html_writer::nonempty_tag('span', get_string('outputnotconfigured', 'message'), array('class' => 'error'));
|
||||
} else if ($processor->enabled) {
|
||||
$url = new moodle_url('/admin/message.php', array('disable' => $processor->id, 'sesskey' => sesskey()));
|
||||
$enable->text = html_writer::link($url, html_writer::empty_tag('img',
|
||||
array('src' => $this->output->pix_url('i/hide'),
|
||||
'class' => 'icon',
|
||||
'title' => get_string('outputenabled', 'message'),
|
||||
'alt' => get_string('outputenabled', 'message'),
|
||||
)
|
||||
));
|
||||
} else {
|
||||
$name->attributes['class'] = 'dimmed_text';
|
||||
$url = new moodle_url('/admin/message.php', array('enable' => $processor->id, 'sesskey' => sesskey()));
|
||||
$enable->text = html_writer::link($url, html_writer::empty_tag('img',
|
||||
array('src' => $this->output->pix_url('i/show'),
|
||||
'class' => 'icon',
|
||||
'title' => get_string('outputdisabled', 'message'),
|
||||
'alt' => get_string('outputdisabled', 'message'),
|
||||
)
|
||||
));
|
||||
}
|
||||
// Settings
|
||||
$settings = new html_table_cell();
|
||||
if ($processor->available && $processor->hassettings) {
|
||||
$settingsurl = new moodle_url('settings.php', array('section' => 'messagesetting'.$processor->name));
|
||||
$settings->text = html_writer::link($settingsurl, get_string('settings', 'message'));
|
||||
}
|
||||
|
||||
$row->cells = array($name, $enable, $settings);
|
||||
$table->data[] = $row;
|
||||
}
|
||||
return html_writer::table($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the interface to manage default message outputs
|
||||
*
|
||||
* @param mixed $processors array of objects containing message processors
|
||||
* @param mixed $providers array of objects containing message providers
|
||||
* @param mixed $preferences array of objects containing current preferences
|
||||
* @return string The text to render
|
||||
*/
|
||||
public function manage_defaultmessageoutputs($processors, $providers, $preferences) {
|
||||
global $CFG;
|
||||
|
||||
// Prepare list of options for dropdown menu
|
||||
$options = array();
|
||||
foreach (array('disallowed', 'permitted', 'forced') as $setting) {
|
||||
$options[$setting] = get_string($setting, 'message');
|
||||
}
|
||||
|
||||
$output = html_writer::start_tag('form', array('id'=>'defaultmessageoutputs', 'method'=>'post'));
|
||||
$output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'sesskey', 'value'=>sesskey()));
|
||||
|
||||
// Display users outputs table
|
||||
$table = new html_table();
|
||||
$table->attributes['class'] = 'generaltable';
|
||||
$table->data = array();
|
||||
$table->head = array('');
|
||||
|
||||
// Populate the header row
|
||||
foreach ($processors as $processor) {
|
||||
$table->head[] = get_string('pluginname', 'message_'.$processor->name);
|
||||
}
|
||||
// Generate the matrix of settings for each provider and processor
|
||||
foreach ($providers as $provider) {
|
||||
$row = new html_table_row();
|
||||
$row->attributes['class'] = 'defaultmessageoutputs';
|
||||
$row->cells = array();
|
||||
|
||||
// Provider Name
|
||||
$providername = get_string('messageprovider:'.$provider->name, $provider->component);
|
||||
$row->cells[] = new html_table_cell($providername);
|
||||
|
||||
// Settings for each processor
|
||||
foreach ($processors as $processor) {
|
||||
$cellcontent = '';
|
||||
foreach (array('permitted', 'loggedin', 'loggedoff') as $setting) {
|
||||
// pepare element and preference names
|
||||
$elementname = $provider->component.'_'.$provider->name.'_'.$setting.'['.$processor->name.']';
|
||||
$preferencebase = $provider->component.'_'.$provider->name.'_'.$setting;
|
||||
// prepare language bits
|
||||
$processorname = get_string('pluginname', 'message_'.$processor->name);
|
||||
$statename = get_string($setting, 'message');
|
||||
$labelparams = array(
|
||||
'provider' => $providername,
|
||||
'processor' => $processorname,
|
||||
'state' => $statename
|
||||
);
|
||||
if ($setting == 'permitted') {
|
||||
$label = get_string('sendingvia', 'message', $labelparams);
|
||||
// determine the current setting or use default
|
||||
$select = MESSAGE_DEFAULT_PERMITTED;
|
||||
$preference = $processor->name.'_provider_'.$preferencebase;
|
||||
if (array_key_exists($preference, $preferences)) {
|
||||
$select = $preferences->{$preference};
|
||||
}
|
||||
// dropdown menu
|
||||
$cellcontent = html_writer::label($label, $elementname, true, array('class' => 'accesshide'));
|
||||
$cellcontent .= html_writer::select($options, $elementname, $select, false, array('id' => $elementname));
|
||||
$cellcontent .= html_writer::tag('div', get_string('defaults', 'message'));
|
||||
} else {
|
||||
$label = get_string('sendingviawhen', 'message', $labelparams);
|
||||
// determine the current setting based on the 'permitted' setting above
|
||||
$checked = false;
|
||||
if ($select == 'forced') {
|
||||
$checked = true;
|
||||
} else if ($select == 'permitted') {
|
||||
$preference = 'message_provider_'.$preferencebase;
|
||||
if (array_key_exists($preference, $preferences)) {
|
||||
$checked = (int)in_array($processor->name, explode(',', $preferences->{$preference}));
|
||||
}
|
||||
}
|
||||
// generate content
|
||||
$cellcontent .= html_writer::start_tag('div');
|
||||
$cellcontent .= html_writer::label($label, $elementname, true, array('class' => 'accesshide'));
|
||||
$cellcontent .= html_writer::checkbox($elementname, 1, $checked, '', array('id' => $elementname));
|
||||
$cellcontent .= $statename;
|
||||
$cellcontent .= html_writer::end_tag('div');
|
||||
}
|
||||
}
|
||||
$row->cells[] = new html_table_cell($cellcontent);
|
||||
}
|
||||
$table->data[] = $row;
|
||||
}
|
||||
|
||||
$output .= html_writer::table($table);
|
||||
$output .= html_writer::start_tag('div', array('class' => 'form-buttons'));
|
||||
$output .= html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('savechanges','admin'), 'class' => 'form-submit'));
|
||||
$output .= html_writer::end_tag('div');
|
||||
$output .= html_writer::end_tag('form');
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the interface for messaging options
|
||||
*
|
||||
* @param mixed $processors array of objects containing message processors
|
||||
* @param mixed $providers array of objects containing message providers
|
||||
* @param mixed $preferences array of objects containing current preferences
|
||||
* @param mixed $defaultpreferences array of objects containing site default preferences
|
||||
* @return string The text to render
|
||||
*/
|
||||
public function manage_messagingoptions($processors, $providers, $preferences, $defaultpreferences) {
|
||||
// Filter out enabled, available system_configured and user_configured processors only.
|
||||
$readyprocessors = array_filter($processors, create_function('$a', 'return $a->enabled && $a->configured && $a->object->is_user_configured();'));
|
||||
|
||||
// Start the form. We're not using mform here because of our special formatting needs ...
|
||||
$output = html_writer::start_tag('form', array('method'=>'post', 'class' => 'mform'));
|
||||
$output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'sesskey', 'value'=>sesskey()));
|
||||
|
||||
/// Settings table...
|
||||
$output .= html_writer::start_tag('fieldset', array('id' => 'providers', 'class' => 'clearfix'));
|
||||
$output .= html_writer::nonempty_tag('legend', get_string('providers_config', 'message'), array('class' => 'ftoggler'));
|
||||
|
||||
// Display the messging options table
|
||||
$table = new html_table();
|
||||
$table->attributes['class'] = 'generaltable';
|
||||
$table->data = array();
|
||||
$table->head = array('');
|
||||
|
||||
foreach ($readyprocessors as $processor) {
|
||||
$table->head[] = get_string('pluginname', 'message_'.$processor->name);
|
||||
}
|
||||
|
||||
$number_procs = count($processors);
|
||||
// Populate the table with rows
|
||||
foreach ( $providers as $provider) {
|
||||
$preferencebase = $provider->component.'_'.$provider->name;
|
||||
|
||||
$headerrow = new html_table_row();
|
||||
$providername = get_string('messageprovider:'.$provider->name, $provider->component);
|
||||
$providercell = new html_table_cell($providername);
|
||||
$providercell->header = true;
|
||||
$providercell->colspan = $number_procs + 1;
|
||||
$providercell->attributes['class'] = 'c0';
|
||||
$headerrow->cells = array($providercell);
|
||||
$table->data[] = $headerrow;
|
||||
|
||||
foreach (array('loggedin', 'loggedoff') as $state) {
|
||||
$optionrow = new html_table_row();
|
||||
$optionname = new html_table_cell(get_string($state.'description', 'message'));
|
||||
$optionname->attributes['class'] = 'c0';
|
||||
$optionrow->cells = array($optionname);
|
||||
foreach ($readyprocessors as $processor) {
|
||||
// determine the default setting
|
||||
$permitted = MESSAGE_DEFAULT_PERMITTED;
|
||||
$defaultpreference = $processor->name.'_provider_'.$preferencebase.'_permitted';
|
||||
if (isset($defaultpreferences->{$defaultpreference})) {
|
||||
$permitted = $defaultpreferences->{$defaultpreference};
|
||||
}
|
||||
// If settings are disallowed, just display the message that
|
||||
// the setting is not permitted, if not use user settings or
|
||||
// force them.
|
||||
if ($permitted == 'disallowed') {
|
||||
if ($state == 'loggedoff') {
|
||||
// skip if we are rendering the second line
|
||||
continue;
|
||||
}
|
||||
$cellcontent = html_writer::nonempty_tag('div', get_string('notpermitted', 'message'), array('class' => 'dimmed_text'));
|
||||
$optioncell = new html_table_cell($cellcontent);
|
||||
$optioncell->rowspan = 2;
|
||||
$optioncell->attributes['class'] = 'disallowed';
|
||||
} else {
|
||||
// determine user preferences and use then unless we force
|
||||
// the preferences.
|
||||
$disabled = array();
|
||||
if ($permitted == 'forced') {
|
||||
$checked = true;
|
||||
$disabled['disabled'] = 1;
|
||||
} else {
|
||||
$checked = false;
|
||||
// See if hser has touched this preference
|
||||
if (isset($preferences->{$preferencebase.'_'.$state})) {
|
||||
// User have some preferneces for this state in the database, use them
|
||||
$checked = isset($preferences->{$preferencebase.'_'.$state}[$processor->name]);
|
||||
} else {
|
||||
// User has not set this preference yet, using site default preferences set by admin
|
||||
$defaultpreference = 'message_provider_'.$preferencebase.'_'.$state;
|
||||
if (isset($defaultpreferences->{$defaultpreference})) {
|
||||
$checked = (int)in_array($processor->name, explode(',', $defaultpreferences->{$defaultpreference}));
|
||||
}
|
||||
}
|
||||
}
|
||||
$elementname = $preferencebase.'_'.$state.'['.$processor->name.']';
|
||||
// prepare language bits
|
||||
$processorname = get_string('pluginname', 'message_'.$processor->name);
|
||||
$statename = get_string($state, 'message');
|
||||
$labelparams = array(
|
||||
'provider' => $providername,
|
||||
'processor' => $processorname,
|
||||
'state' => $statename
|
||||
);
|
||||
$label = get_string('sendingviawhen', 'message', $labelparams);
|
||||
$cellcontent = html_writer::label($label, $elementname, true, array('class' => 'accesshide'));
|
||||
$cellcontent .= html_writer::checkbox($elementname, 1, $checked, '', array_merge(array('id' => $elementname), $disabled));
|
||||
$optioncell = new html_table_cell($cellcontent);
|
||||
$optioncell->attributes['class'] = 'mdl-align';
|
||||
}
|
||||
$optionrow->cells[] = $optioncell;
|
||||
}
|
||||
$table->data[] = $optionrow;
|
||||
}
|
||||
}
|
||||
$output .= html_writer::start_tag('div');
|
||||
$output .= html_writer::table($table);
|
||||
$output .= html_writer::end_tag('div');
|
||||
$output .= html_writer::end_tag('fieldset');
|
||||
|
||||
foreach ($processors as $processor) {
|
||||
if (($processorconfigform = $processor->object->config_form($preferences)) && $processor->enabled) {
|
||||
$output .= html_writer::start_tag('fieldset', array('id' => 'messageprocessor_'.$processor->name, 'class' => 'clearfix'));
|
||||
$output .= html_writer::nonempty_tag('legend', get_string('pluginname', 'message_'.$processor->name), array('class' => 'ftoggler'));
|
||||
$output .= html_writer::start_tag('div');
|
||||
$output .= $processorconfigform;
|
||||
$output .= html_writer::end_tag('div');
|
||||
$output .= html_writer::end_tag('fieldset');
|
||||
}
|
||||
}
|
||||
|
||||
$output .= html_writer::start_tag('fieldset', array('id' => 'messageprocessor_general', 'class' => 'clearfix'));
|
||||
$output .= html_writer::nonempty_tag('legend', get_string('generalsettings','admin'), array('class' => 'ftoggler'));
|
||||
$output .= html_writer::start_tag('div');
|
||||
$output .= get_string('blocknoncontacts', 'message').': ';
|
||||
$output .= html_writer::checkbox('blocknoncontacts', 1, $preferences->blocknoncontacts, '');
|
||||
$output .= html_writer::end_tag('div');
|
||||
$output .= html_writer::end_tag('fieldset');
|
||||
$output .= html_writer::start_tag('div', array('class' => 'mdl-align'));
|
||||
$output .= html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('updatemyprofile'), 'class' => 'form-submit'));
|
||||
$output .= html_writer::end_tag('div');
|
||||
$output .= html_writer::end_tag('form');
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
@ -971,8 +971,7 @@ class assignment_base {
|
||||
$userfields = user_picture::fields('u', array('lastaccess'));
|
||||
$select = "SELECT $userfields,
|
||||
s.id AS submissionid, s.grade, s.submissioncomment,
|
||||
s.timemodified, s.timemarked,
|
||||
COALESCE(SIGN(SIGN(s.timemarked) + SIGN(s.timemarked - s.timemodified)), 0) AS status ";
|
||||
s.timemodified, s.timemarked ";
|
||||
$sql = 'FROM {user} u '.
|
||||
'LEFT JOIN {assignment_submissions} s ON u.id = s.userid
|
||||
AND s.assignment = '.$this->assignment->id.' '.
|
||||
@ -1285,8 +1284,7 @@ class assignment_base {
|
||||
if (!empty($users)) {
|
||||
$select = "SELECT $ufields,
|
||||
s.id AS submissionid, s.grade, s.submissioncomment,
|
||||
s.timemodified, s.timemarked,
|
||||
COALESCE(SIGN(SIGN(s.timemarked) + SIGN(s.timemarked - s.timemodified)), 0) AS status ";
|
||||
s.timemodified, s.timemarked ";
|
||||
$sql = 'FROM {user} u '.
|
||||
'LEFT JOIN {assignment_submissions} s ON u.id = s.userid
|
||||
AND s.assignment = '.$this->assignment->id.' '.
|
||||
|
@ -84,6 +84,7 @@ $string['completionreplies'] = 'Student must post replies:';
|
||||
$string['completionrepliesgroup'] = 'Require replies';
|
||||
$string['completionreplieshelp'] = 'requiring replies to complete';
|
||||
$string['configcleanreadtime'] = 'The hour of the day to clean old posts from the \'read\' table.';
|
||||
$string['configdigestmailtime'] = 'People who choose to have emails sent to them in digest form will be emailed the digest daily. This setting controls which time of day the daily mail will be sent (the next cron that runs after this hour will send it).';
|
||||
$string['configdisplaymode'] = 'The default display mode for discussions if one isn\'t set.';
|
||||
$string['configenablerssfeeds'] = 'This switch will enable the possibility of RSS feeds for all forums. You will still need to turn feeds on manually in the settings for each forum.';
|
||||
$string['configenabletimedposts'] = 'Set to \'yes\' if you want to allow setting of display periods when posting a new forum discussion (Experimental as not yet fully tested)';
|
||||
@ -110,6 +111,7 @@ $string['deletesureplural'] = 'Are you sure you want to delete this post and all
|
||||
$string['digestmailheader'] = 'This is your daily digest of new posts from the {$a->sitename} forums. To change your forum email preferences, go to {$a->userprefs}.';
|
||||
$string['digestmailprefs'] = 'your user profile';
|
||||
$string['digestmailsubject'] = '{$a}: forum digest';
|
||||
$string['digestmailtime'] = 'Hour to send digest emails';
|
||||
$string['digestsentusers'] = 'Email digests successfully sent to {$a} users.';
|
||||
$string['disallowsubscribe'] = 'Subscriptions not allowed';
|
||||
$string['disallowsubscribeteacher'] = 'Subscriptions not allowed (except for teachers)';
|
||||
|
@ -65,14 +65,17 @@ if ($ADMIN->fulltree) {
|
||||
$settings->add(new admin_setting_configcheckbox('forum_usermarksread', get_string('usermarksread', 'forum'),
|
||||
get_string('configusermarksread', 'forum'), 0));
|
||||
|
||||
// Default time (hour) to execute 'clean_read_records' cron
|
||||
$options = array();
|
||||
for ($i=0; $i<24; $i++) {
|
||||
$options[$i] = $i;
|
||||
for ($i = 0; $i < 24; $i++) {
|
||||
$options[$i] = sprintf("%02d",$i);
|
||||
}
|
||||
// Default time (hour) to execute 'clean_read_records' cron
|
||||
$settings->add(new admin_setting_configselect('forum_cleanreadtime', get_string('cleanreadtime', 'forum'),
|
||||
get_string('configcleanreadtime', 'forum'), 2, $options));
|
||||
|
||||
// Default time (hour) to send digest email
|
||||
$settings->add(new admin_setting_configselect('digestmailtime', get_string('digestmailtime', 'forum'),
|
||||
get_string('configdigestmailtime', 'forum'), 17, $options));
|
||||
|
||||
if (empty($CFG->enablerssfeeds)) {
|
||||
$options = array(0 => get_string('rssglobaldisabled', 'admin'));
|
||||
|
@ -38,7 +38,7 @@ class backup_glossary_activity_structure_step extends backup_activity_structure_
|
||||
|
||||
// Define each element separated
|
||||
$glossary = new backup_nested_element('glossary', array('id'), array(
|
||||
'name', 'intro', 'allowduplicatedentries', 'displayformat',
|
||||
'name', 'intro', 'introformat', 'allowduplicatedentries', 'displayformat',
|
||||
'mainglossary', 'showspecial', 'showalphabet', 'showall',
|
||||
'allowcomments', 'allowprintview', 'usedynalink', 'defaultapproval',
|
||||
'globalglossary', 'entbypage', 'editalways', 'rsstype',
|
||||
|
@ -1,7 +1,38 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Classes to enforce the various access rules that can apply to a quiz.
|
||||
*
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* This class keeps track of the various access rules that apply to a particular
|
||||
* quiz, with convinient methods for seeing whether access is allowed.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quiz_access_manager {
|
||||
private $_quizobj;
|
||||
@ -15,8 +46,8 @@ class quiz_access_manager {
|
||||
* Create an instance for a particular quiz.
|
||||
* @param object $quizobj An instance of the class quiz from attemptlib.php.
|
||||
* The quiz we will be controlling access to.
|
||||
* @param integer $timenow The time to use as 'now'.
|
||||
* @param boolean $canignoretimelimits Whether this user is exempt from time
|
||||
* @param int $timenow The time to use as 'now'.
|
||||
* @param bool $canignoretimelimits Whether this user is exempt from time
|
||||
* limits (has_capability('mod/quiz:ignoretimelimits', ...)).
|
||||
*/
|
||||
public function __construct($quizobj, $timenow, $canignoretimelimits) {
|
||||
@ -46,10 +77,12 @@ class quiz_access_manager {
|
||||
}
|
||||
if (!empty($quiz->popup)) {
|
||||
if ($quiz->popup == 1) {
|
||||
$this->_securewindowrule = new securewindow_access_rule($this->_quizobj, $this->_timenow);
|
||||
$this->_securewindowrule = new securewindow_access_rule(
|
||||
$this->_quizobj, $this->_timenow);
|
||||
$this->_rules[] = $this->_securewindowrule;
|
||||
} elseif ($quiz->popup == 2) {
|
||||
$this->_safebrowserrule = new safebrowser_access_rule($this->_quizobj, $this->_timenow);
|
||||
} else if ($quiz->popup == 2) {
|
||||
$this->_safebrowserrule = new safebrowser_access_rule(
|
||||
$this->_quizobj, $this->_timenow);
|
||||
$this->_rules[] = $this->_safebrowserrule;
|
||||
}
|
||||
}
|
||||
@ -63,27 +96,6 @@ class quiz_access_manager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print each message in an array, surrounded by <p>, </p> tags.
|
||||
*
|
||||
* @param array $messages the array of message strings.
|
||||
* @param boolean $return if true, return a string, instead of outputting.
|
||||
*
|
||||
* @return mixed, if $return is true, return the string that would have been output, otherwise
|
||||
* return null.
|
||||
*/
|
||||
public function print_messages($messages, $return=false) {
|
||||
$output = '';
|
||||
foreach ($messages as $message) {
|
||||
$output .= '<p>' . $message . "</p>\n";
|
||||
}
|
||||
if ($return) {
|
||||
return $output;
|
||||
} else {
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a description of the rules that apply to this quiz, such
|
||||
* as is shown at the top of the quiz view page. Note that not all
|
||||
@ -105,7 +117,7 @@ class quiz_access_manager {
|
||||
* any restrictions in force now, return an array of reasons why access
|
||||
* should be blocked. If access is OK, return false.
|
||||
*
|
||||
* @param integer $numattempts the number of previous attempts this user has made.
|
||||
* @param int $numattempts the number of previous attempts this user has made.
|
||||
* @param object|false $lastattempt information about the user's last completed attempt.
|
||||
* if there is not a previous attempt, the false is passed.
|
||||
* @return mixed An array of reason why access is not allowed, or an empty array
|
||||
@ -139,11 +151,12 @@ class quiz_access_manager {
|
||||
/**
|
||||
* Do any of the rules mean that this student will no be allowed any further attempts at this
|
||||
* quiz. Used, for example, to change the label by the grade displayed on the view page from
|
||||
* 'your current score is' to 'your final score is'.
|
||||
* 'your current grade is' to 'your final grade is'.
|
||||
*
|
||||
* @param integer $numattempts the number of previous attempts this user has made.
|
||||
* @param int $numattempts the number of previous attempts this user has made.
|
||||
* @param object $lastattempt information about the user's last completed attempt.
|
||||
* @return boolean true if there is no way the user will ever be allowed to attempt this quiz again.
|
||||
* @return bool true if there is no way the user will ever be allowed to attempt
|
||||
* this quiz again.
|
||||
*/
|
||||
public function is_finished($numprevattempts, $lastattempt) {
|
||||
foreach ($this->_rules as $rule) {
|
||||
@ -174,8 +187,8 @@ class quiz_access_manager {
|
||||
}
|
||||
}
|
||||
if ($timeleft !== false) {
|
||||
/// Make sure the timer starts just above zero. If $timeleft was <= 0, then
|
||||
/// this will just have the effect of causing the quiz to be submitted immediately.
|
||||
// Make sure the timer starts just above zero. If $timeleft was <= 0, then
|
||||
// this will just have the effect of causing the quiz to be submitted immediately.
|
||||
$timerstartvalue = max($timeleft, 1);
|
||||
$PAGE->requires->js_init_call('M.mod_quiz.timer.init',
|
||||
array($timerstartvalue), false, quiz_get_js_module());
|
||||
@ -201,12 +214,13 @@ class quiz_access_manager {
|
||||
* depending on the access restrictions. The link will pop up a 'secure' window, if
|
||||
* necessary.
|
||||
*
|
||||
* @param boolean $canpreview whether this user can preview. This affects whether they must
|
||||
* @param bool $canpreview whether this user can preview. This affects whether they must
|
||||
* use a secure window.
|
||||
* @param string $buttontext the label to put on the button.
|
||||
* @param boolean $unfinished whether the button is to continue an existing attempt,
|
||||
* @param bool $unfinished whether the button is to continue an existing attempt,
|
||||
* or start a new one. This affects whether a javascript alert is shown.
|
||||
*/
|
||||
//TODO: Add this function to renderer
|
||||
public function print_start_attempt_button($canpreview, $buttontext, $unfinished) {
|
||||
global $OUTPUT;
|
||||
|
||||
@ -233,14 +247,14 @@ class quiz_access_manager {
|
||||
$OUTPUT->heading(get_string('noscript', 'quiz')));
|
||||
}
|
||||
|
||||
echo $OUTPUT->render($button) . $warning;
|
||||
return $OUTPUT->render($button) . $warning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the user back to the quiz view page. Normally this is just a redirect, but
|
||||
* If we were in a secure window, we close this window, and reload the view window we came from.
|
||||
*
|
||||
* @param boolean $canpreview This affects whether we have to worry about secure window stuff.
|
||||
* @param bool $canpreview This affects whether we have to worry about secure window stuff.
|
||||
*/
|
||||
public function back_to_view_page($canpreview, $message = '') {
|
||||
global $CFG, $OUTPUT, $PAGE;
|
||||
@ -256,7 +270,8 @@ class quiz_access_manager {
|
||||
echo '<p>' . get_string('pleaseclose', 'quiz') . '</p>';
|
||||
$delay = 0;
|
||||
}
|
||||
$PAGE->requires->js_function_call('M.mod_quiz.secure_window.close', array($url, $delay));
|
||||
$PAGE->requires->js_function_call('M.mod_quiz.secure_window.close',
|
||||
array($url, $delay));
|
||||
echo $OUTPUT->box_end();
|
||||
echo $OUTPUT->footer();
|
||||
die();
|
||||
@ -269,7 +284,7 @@ class quiz_access_manager {
|
||||
* Print a control to finish the review. Normally this is just a link, but if we are
|
||||
* in a secure window, it needs to be a button that does M.mod_quiz.secure_window.close.
|
||||
*
|
||||
* @param boolean $canpreview This affects whether we have to worry about secure window stuff.
|
||||
* @param bool $canpreview This affects whether we have to worry about secure window stuff.
|
||||
*/
|
||||
public function print_finish_review_link($canpreview, $return = false) {
|
||||
global $CFG;
|
||||
@ -311,7 +326,7 @@ class quiz_access_manager {
|
||||
* Actually ask the user for the password, if they have not already given it this session.
|
||||
* This function only returns is access is OK.
|
||||
*
|
||||
* @param boolean $canpreview used to enfore securewindow stuff.
|
||||
* @param bool $canpreview used to enfore securewindow stuff.
|
||||
*/
|
||||
public function do_password_check($canpreview) {
|
||||
if (!is_null($this->_passwordrule)) {
|
||||
@ -326,11 +341,11 @@ class quiz_access_manager {
|
||||
public function confirm_start_attempt_message() {
|
||||
$quiz = $this->_quizobj->get_quiz();
|
||||
if ($quiz->timelimit && $quiz->attempts) {
|
||||
return get_string('confirmstartattempttimelimit','quiz', $quiz->attempts);
|
||||
return get_string('confirmstartattempttimelimit', 'quiz', $quiz->attempts);
|
||||
} else if ($quiz->timelimit) {
|
||||
return get_string('confirmstarttimelimit','quiz');
|
||||
return get_string('confirmstarttimelimit', 'quiz');
|
||||
} else if ($quiz->attempts) {
|
||||
return get_string('confirmstartattemptlimit','quiz', $quiz->attempts);
|
||||
return get_string('confirmstartattemptlimit', 'quiz', $quiz->attempts);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
@ -340,17 +355,23 @@ class quiz_access_manager {
|
||||
*
|
||||
* @param string $linktext some text.
|
||||
* @param object $attempt the attempt object
|
||||
* @return string some HTML, the $linktext either unmodified or wrapped in a link to the review page.
|
||||
* @return string some HTML, the $linktext either unmodified or wrapped in a
|
||||
* link to the review page.
|
||||
*/
|
||||
public function make_review_link($attempt, $canpreview, $reviewoptions) {
|
||||
global $CFG;
|
||||
|
||||
/// If review of responses is not allowed, or the attempt is still open, don't link.
|
||||
// If review of responses is not allowed, or the attempt is still open, don't link.
|
||||
if (!$attempt->timefinish) {
|
||||
return '';
|
||||
}
|
||||
if (!$reviewoptions->responses) {
|
||||
$message = $this->cannot_review_message($reviewoptions, true);
|
||||
|
||||
$when = quiz_attempt_state($this->_quizobj->get_quiz(), $attempt);
|
||||
$reviewoptions = mod_quiz_display_options::make_from_quiz(
|
||||
$this->_quizobj->get_quiz(), $when);
|
||||
|
||||
if (!$reviewoptions->attempt) {
|
||||
$message = $this->cannot_review_message($when, true);
|
||||
if ($message) {
|
||||
return '<span class="noreviewmessage">' . $message . '</span>';
|
||||
} else {
|
||||
@ -360,7 +381,7 @@ class quiz_access_manager {
|
||||
|
||||
$linktext = get_string('review', 'quiz');
|
||||
|
||||
/// It is OK to link, does it need to be in a secure window?
|
||||
// It is OK to link, does it need to be in a secure window?
|
||||
if ($this->securewindow_required($canpreview)) {
|
||||
return $this->_securewindowrule->make_review_link($linktext, $attempt->id);
|
||||
} else {
|
||||
@ -370,14 +391,15 @@ class quiz_access_manager {
|
||||
}
|
||||
|
||||
/**
|
||||
* If $reviewoptions->responses is false, meaning that students can't review this
|
||||
* If $reviewoptions->attempt is false, meaning that students can't review this
|
||||
* attempt at the moment, return an appropriate string explaining why.
|
||||
*
|
||||
* @param object $reviewoptions as obtained from quiz_get_reviewoptions.
|
||||
* @param boolean $short if true, return a shorter string.
|
||||
* @param int $when One of the mod_quiz_display_options::DURING,
|
||||
* IMMEDIATELY_AFTER, LATER_WHILE_OPEN or AFTER_CLOSE constants.
|
||||
* @param bool $short if true, return a shorter string.
|
||||
* @return string an appropraite message.
|
||||
*/
|
||||
public function cannot_review_message($reviewoptions, $short = false) {
|
||||
public function cannot_review_message($when, $short = false) {
|
||||
$quiz = $this->_quizobj->get_quiz();
|
||||
if ($short) {
|
||||
$langstrsuffix = 'short';
|
||||
@ -386,17 +408,20 @@ class quiz_access_manager {
|
||||
$langstrsuffix = '';
|
||||
$dateformat = '';
|
||||
}
|
||||
if ($reviewoptions->quizstate == QUIZ_STATE_IMMEDIATELY) {
|
||||
if ($when == mod_quiz_display_options::DURING ||
|
||||
$when == mod_quiz_display_options::IMMEDIATELY_AFTER) {
|
||||
return '';
|
||||
} else if ($reviewoptions->quizstate == QUIZ_STATE_OPEN && $quiz->timeclose &&
|
||||
($quiz->review & QUIZ_REVIEW_CLOSED & QUIZ_REVIEW_RESPONSES)) {
|
||||
return get_string('noreviewuntil' . $langstrsuffix, 'quiz', userdate($quiz->timeclose, $dateformat));
|
||||
} else if ($when == mod_quiz_display_options::LATER_WHILE_OPEN && $quiz->timeclose &&
|
||||
$quiz->reviewattempt & mod_quiz_display_options::AFTER_CLOSE) {
|
||||
return get_string('noreviewuntil' . $langstrsuffix, 'quiz',
|
||||
userdate($quiz->timeclose, $dateformat));
|
||||
} else {
|
||||
return get_string('noreview' . $langstrsuffix, 'quiz');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A base class that defines the interface for the various quiz access rules.
|
||||
* Most of the methods are defined in a slightly unnatural way because we either
|
||||
@ -405,6 +430,9 @@ class quiz_access_manager {
|
||||
* return false if access is permitted, or a string explanation (which is treated
|
||||
* as true) if access should be blocked. Slighly unnatural, but acutally the easist
|
||||
* way to implement this.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class quiz_access_rule_base {
|
||||
protected $_quiz;
|
||||
@ -421,16 +449,18 @@ abstract class quiz_access_rule_base {
|
||||
}
|
||||
/**
|
||||
* Whether or not a user should be allowed to start a new attempt at this quiz now.
|
||||
* @param integer $numattempts the number of previous attempts this user has made.
|
||||
* @param int $numattempts the number of previous attempts this user has made.
|
||||
* @param object $lastattempt information about the user's last completed attempt.
|
||||
* @return string false if access should be allowed, a message explaining the reason if access should be prevented.
|
||||
* @return string false if access should be allowed, a message explaining the
|
||||
* reason if access should be prevented.
|
||||
*/
|
||||
public function prevent_new_attempt($numprevattempts, $lastattempt) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Whether or not a user should be allowed to start a new attempt at this quiz now.
|
||||
* @return string false if access should be allowed, a message explaining the reason if access should be prevented.
|
||||
* @return string false if access should be allowed, a message explaining the
|
||||
* reason if access should be prevented.
|
||||
*/
|
||||
public function prevent_access() {
|
||||
return false;
|
||||
@ -448,11 +478,11 @@ abstract class quiz_access_rule_base {
|
||||
/**
|
||||
* If this rule can determine that this user will never be allowed another attempt at
|
||||
* this quiz, then return true. This is used so we can know whether to display a
|
||||
* final score on the view page. This will only be called if there is not a currently
|
||||
* final grade on the view page. This will only be called if there is not a currently
|
||||
* active attempt for this user.
|
||||
* @param integer $numattempts the number of previous attempts this user has made.
|
||||
* @param int $numattempts the number of previous attempts this user has made.
|
||||
* @param object $lastattempt information about the user's last completed attempt.
|
||||
* @return boolean true if this rule means that this user will never be allowed another
|
||||
* @return bool true if this rule means that this user will never be allowed another
|
||||
* attempt at this quiz.
|
||||
*/
|
||||
public function is_finished($numprevattempts, $lastattempt) {
|
||||
@ -463,7 +493,7 @@ abstract class quiz_access_rule_base {
|
||||
* If, becuase of this rule, the user has to finish their attempt by a certain time,
|
||||
* you should override this method to return the amount of time left in seconds.
|
||||
* @param object $attempt the current attempt
|
||||
* @param integer $timenow the time now. We don't use $this->_timenow, so we can
|
||||
* @param int $timenow the time now. We don't use $this->_timenow, so we can
|
||||
* give the user a more accurate indication of how much time is left.
|
||||
* @return mixed false if there is no deadline, of the time left in seconds if there is one.
|
||||
*/
|
||||
@ -474,6 +504,9 @@ abstract class quiz_access_rule_base {
|
||||
|
||||
/**
|
||||
* A rule controlling the number of attempts allowed.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class num_attempts_access_rule extends quiz_access_rule_base {
|
||||
public function description() {
|
||||
@ -492,6 +525,9 @@ class num_attempts_access_rule extends quiz_access_rule_base {
|
||||
|
||||
/**
|
||||
* A rule enforcing open and close dates.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class open_close_date_access_rule extends quiz_access_rule_base {
|
||||
public function description() {
|
||||
@ -540,16 +576,19 @@ class open_close_date_access_rule extends quiz_access_rule_base {
|
||||
}
|
||||
|
||||
/**
|
||||
* A rule imposing the delay between attemtps settings.
|
||||
* A rule imposing the delay between attempts settings.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class inter_attempt_delay_access_rule extends quiz_access_rule_base {
|
||||
public function prevent_new_attempt($numprevattempts, $lastattempt) {
|
||||
if ($this->_quiz->attempts > 0 && $numprevattempts >= $this->_quiz->attempts) {
|
||||
/// No more attempts allowed anyway.
|
||||
// No more attempts allowed anyway.
|
||||
return false;
|
||||
}
|
||||
if ($this->_quiz->timeclose != 0 && $this->_timenow > $this->_quiz->timeclose) {
|
||||
/// No more attempts allowed anyway.
|
||||
// No more attempts allowed anyway.
|
||||
return false;
|
||||
}
|
||||
$nextstarttime = $this->compute_next_start_time($numprevattempts, $lastattempt);
|
||||
@ -566,7 +605,7 @@ class inter_attempt_delay_access_rule extends quiz_access_rule_base {
|
||||
/**
|
||||
* Compute the next time a student would be allowed to start an attempt,
|
||||
* according to this rule.
|
||||
* @param integer $numprevattempts number of previous attempts.
|
||||
* @param int $numprevattempts number of previous attempts.
|
||||
* @param object $lastattempt information about the previous attempt.
|
||||
* @return number the time.
|
||||
*/
|
||||
@ -576,7 +615,7 @@ class inter_attempt_delay_access_rule extends quiz_access_rule_base {
|
||||
}
|
||||
|
||||
$lastattemptfinish = $lastattempt->timefinish;
|
||||
if ($this->_quiz->timelimit > 0){
|
||||
if ($this->_quiz->timelimit > 0) {
|
||||
$lastattemptfinish = min($lastattemptfinish,
|
||||
$lastattempt->timestart + $this->_quiz->timelimit);
|
||||
}
|
||||
@ -598,6 +637,9 @@ class inter_attempt_delay_access_rule extends quiz_access_rule_base {
|
||||
|
||||
/**
|
||||
* A rule implementing the ipaddress check against the ->submet setting.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class ipaddress_access_rule extends quiz_access_rule_base {
|
||||
public function prevent_access() {
|
||||
@ -612,6 +654,9 @@ class ipaddress_access_rule extends quiz_access_rule_base {
|
||||
/**
|
||||
* A rule representing the password check. It does not actually implement the check,
|
||||
* that has to be done directly in attempt.php, but this facilitates telling users about it.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class password_access_rule extends quiz_access_rule_base {
|
||||
public function description() {
|
||||
@ -630,23 +675,24 @@ class password_access_rule extends quiz_access_rule_base {
|
||||
* Actually ask the user for the password, if they have not already given it this session.
|
||||
* This function only returns is access is OK.
|
||||
*
|
||||
* @param boolean $canpreview used to enfore securewindow stuff.
|
||||
* @param bool $canpreview used to enfore securewindow stuff.
|
||||
* @param object $accessmanager the accessmanager calling us.
|
||||
* @return mixed return null, unless $return is true, and a form needs to be displayed.
|
||||
*/
|
||||
public function do_password_check($canpreview, $accessmanager) {
|
||||
global $CFG, $SESSION, $OUTPUT, $PAGE;
|
||||
|
||||
/// We have already checked the password for this quiz this session, so don't ask again.
|
||||
// We have already checked the password for this quiz this session, so don't ask again.
|
||||
if (!empty($SESSION->passwordcheckedquizzes[$this->_quiz->id])) {
|
||||
return;
|
||||
}
|
||||
|
||||
/// If the user cancelled the password form, send them back to the view page.
|
||||
// If the user cancelled the password form, send them back to the view page.
|
||||
if (optional_param('cancelpassword', false, PARAM_BOOL)) {
|
||||
$accessmanager->back_to_view_page($canpreview);
|
||||
}
|
||||
|
||||
/// If they entered the right password, let them in.
|
||||
// If they entered the right password, let them in.
|
||||
$enteredpassword = optional_param('quizpassword', '', PARAM_RAW);
|
||||
$validpassword = false;
|
||||
if (strcmp($this->_quiz->password, $enteredpassword) === 0) {
|
||||
@ -665,15 +711,16 @@ class password_access_rule extends quiz_access_rule_base {
|
||||
return;
|
||||
}
|
||||
|
||||
/// User entered the wrong password, or has not entered one yet, so display the form.
|
||||
// User entered the wrong password, or has not entered one yet, so display the form.
|
||||
$output = '';
|
||||
|
||||
/// Start the page and print the quiz intro, if any.
|
||||
// Start the page and print the quiz intro, if any.
|
||||
if ($accessmanager->securewindow_required($canpreview)) {
|
||||
$accessmanager->setup_secure_page($this->_quizobj->get_course()->shortname . ': ' .
|
||||
format_string($this->_quizobj->get_quiz_name()));
|
||||
} else if ($accessmanager->safebrowser_required($canpreview)) {
|
||||
$PAGE->set_title($this->_quizobj->get_course()->shortname . ': '.format_string($this->_quizobj->get_quiz_name()));
|
||||
$PAGE->set_title($this->_quizobj->get_course()->shortname . ': ' .
|
||||
format_string($this->_quizobj->get_quiz_name()));
|
||||
$PAGE->set_cacheable(false);
|
||||
echo $OUTPUT->header();
|
||||
} else {
|
||||
@ -682,16 +729,17 @@ class password_access_rule extends quiz_access_rule_base {
|
||||
}
|
||||
|
||||
if (trim(strip_tags($this->_quiz->intro))) {
|
||||
$output .= $OUTPUT->box(format_module_intro('quiz', $this->_quiz, $this->_quizobj->get_cmid()), 'generalbox', 'intro');
|
||||
$output .= $OUTPUT->box(format_module_intro('quiz', $this->_quiz,
|
||||
$this->_quizobj->get_cmid()), 'generalbox', 'intro');
|
||||
}
|
||||
$output .= $OUTPUT->box_start('generalbox', 'passwordbox');
|
||||
|
||||
/// If they have previously tried and failed to enter a password, tell them it was wrong.
|
||||
// If they have previously tried and failed to enter a password, tell them it was wrong.
|
||||
if (!empty($enteredpassword)) {
|
||||
$output .= '<p class="notifyproblem">' . get_string('passworderror', 'quiz') . '</p>';
|
||||
}
|
||||
|
||||
/// Print the password entry form.
|
||||
// Print the password entry form.
|
||||
$output .= '<p>' . get_string('requirepasswordmessage', 'quiz') . "</p>\n";
|
||||
$output .= '<form id="passwordform" method="post" action="' . $CFG->wwwroot .
|
||||
'/mod/quiz/startattempt.php" onclick="this.autocomplete=\'off\'">' . "\n";
|
||||
@ -707,10 +755,10 @@ class password_access_rule extends quiz_access_rule_base {
|
||||
$output .= "</div>\n";
|
||||
$output .= "</form>\n";
|
||||
|
||||
/// Finish page.
|
||||
// Finish page.
|
||||
$output .= $OUTPUT->box_end();
|
||||
|
||||
/// return or display form.
|
||||
// return or display form.
|
||||
echo $output;
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
@ -720,6 +768,9 @@ class password_access_rule extends quiz_access_rule_base {
|
||||
/**
|
||||
* A rule representing the time limit. It does not actually restrict access, but we use this
|
||||
* class to encapsulate some of the relevant code.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class time_limit_access_rule extends quiz_access_rule_base {
|
||||
public function description() {
|
||||
@ -733,6 +784,9 @@ class time_limit_access_rule extends quiz_access_rule_base {
|
||||
/**
|
||||
* A rule for ensuring that the quiz is opened in a popup, with some JavaScript
|
||||
* to prevent copying and pasting, etc.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class securewindow_access_rule extends quiz_access_rule_base {
|
||||
/**
|
||||
@ -756,7 +810,7 @@ class securewindow_access_rule extends quiz_access_rule_base {
|
||||
* Make a link to the review page for an attempt.
|
||||
*
|
||||
* @param string $linktext the desired link text.
|
||||
* @param integer $attemptid the attempt id.
|
||||
* @param int $attemptid the attempt id.
|
||||
* @return string HTML for the link.
|
||||
*/
|
||||
public function make_review_link($linktext, $attemptid) {
|
||||
@ -787,9 +841,13 @@ class securewindow_access_rule extends quiz_access_rule_base {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A rule representing the safe browser check.
|
||||
*/
|
||||
*
|
||||
* @copyright 2009 Oliver Rahs
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class safebrowser_access_rule extends quiz_access_rule_base {
|
||||
public function prevent_access() {
|
||||
if (!$this->_quizobj->is_preview_user() && !quiz_check_safe_browser()) {
|
||||
@ -803,4 +861,3 @@ class safebrowser_access_rule extends quiz_access_rule_base {
|
||||
return get_string("safebrowsernotice", "quiz");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,30 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Fallback page of /mod/quiz/edit.php add random question dialog,
|
||||
* for users who do not use javascript.
|
||||
*
|
||||
* @author Olli Savolainen, as a part of the Quiz UI Redesign project in Summer 2008
|
||||
* {@link http://docs.moodle.org/en/Development:Quiz_UI_redesign}.
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @package quiz
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
* @copyright 2008 Olli Savolainen
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
require_once('../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/editlib.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/addrandomform.php');
|
||||
@ -21,6 +38,7 @@ list($thispageurl, $contexts, $cmid, $cm, $quiz, $pagevars) =
|
||||
$returnurl = optional_param('returnurl', '', PARAM_LOCALURL);
|
||||
$addonpage = optional_param('addonpage', 0, PARAM_INT);
|
||||
$category = optional_param('category', 0, PARAM_INT);
|
||||
$scrollpos = optional_param('scrollpos', 0, PARAM_INT);
|
||||
|
||||
// Get the course object and related bits.
|
||||
if (!$course = $DB->get_record('course', array('id' => $quiz->course))) {
|
||||
@ -36,6 +54,9 @@ if ($returnurl) {
|
||||
} else {
|
||||
$returnurl = new moodle_url('/mod/quiz/edit.php', array('cmid' => $cmid));
|
||||
}
|
||||
if ($scrollpos) {
|
||||
$returnurl->param('scrollpos', $scrollpos);
|
||||
}
|
||||
|
||||
$defaultcategoryobj = question_make_default_categories($contexts->all());
|
||||
$defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
|
||||
@ -70,7 +91,8 @@ if ($data = $mform->get_data()) {
|
||||
$returnurl->param('cat', $categoryid . ',' . $contextid);
|
||||
|
||||
} else {
|
||||
throw new coding_exception('It seems a form was submitted without any button being pressed???');
|
||||
throw new coding_exception(
|
||||
'It seems a form was submitted without any button being pressed???');
|
||||
}
|
||||
|
||||
quiz_add_random_questions($quiz, $addonpage, $categoryid, 1, $includesubcategories);
|
||||
|
@ -1,17 +1,51 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Defines the Moodle forum used to add random questions to the quiz.
|
||||
*
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
* @copyright 2008 Olli Savolainen
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir.'/formslib.php');
|
||||
|
||||
|
||||
/**
|
||||
* The add random questions form.
|
||||
*
|
||||
* @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quiz_add_random_form extends moodleform {
|
||||
|
||||
function definition() {
|
||||
protected function definition() {
|
||||
global $CFG, $DB;
|
||||
$mform =& $this->_form;
|
||||
|
||||
$contexts = $this->_customdata;
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
$mform->addElement('header', 'categoryheader', get_string('randomfromexistingcategory', 'quiz'));
|
||||
//--------------------------------------------------------------------------------
|
||||
$mform->addElement('header', 'categoryheader',
|
||||
get_string('randomfromexistingcategory', 'quiz'));
|
||||
|
||||
$mform->addElement('questioncategory', 'category', get_string('category'),
|
||||
array('contexts' => $contexts->all(), 'top' => false));
|
||||
@ -20,8 +54,9 @@ class quiz_add_random_form extends moodleform {
|
||||
|
||||
$mform->addElement('submit', 'existingcategory', get_string('addrandomquestion', 'quiz'));
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
$mform->addElement('header', 'categoryheader', get_string('randomquestionusinganewcategory', 'quiz'));
|
||||
//--------------------------------------------------------------------------------
|
||||
$mform->addElement('header', 'categoryheader',
|
||||
get_string('randomquestionusinganewcategory', 'quiz'));
|
||||
|
||||
$mform->addElement('text', 'name', get_string('name'), 'maxlength="254" size="50"');
|
||||
$mform->setType('name', PARAM_MULTILANG);
|
||||
@ -30,9 +65,10 @@ class quiz_add_random_form extends moodleform {
|
||||
array('contexts' => $contexts->all(), 'top' => true));
|
||||
$mform->addHelpButton('parent', 'parentcategory', 'question');
|
||||
|
||||
$mform->addElement('submit', 'newcategory', get_string('createcategoryandaddrandomquestion', 'quiz'));
|
||||
$mform->addElement('submit', 'newcategory',
|
||||
get_string('createcategoryandaddrandomquestion', 'quiz'));
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------------------
|
||||
$mform->addElement('cancel');
|
||||
$mform->closeHeaderBefore('cancel');
|
||||
|
||||
@ -44,11 +80,11 @@ class quiz_add_random_form extends moodleform {
|
||||
$mform->setType('returnurl', PARAM_LOCALURL);
|
||||
}
|
||||
|
||||
function validation($fromform, $files) {
|
||||
public function validation($fromform, $files) {
|
||||
$errors = parent::validation($fromform, $files);
|
||||
|
||||
if (!empty($fromform['newcategory']) && trim($fromform['name']) == '') {
|
||||
$errors['name'] = get_string('categorynamecantbeblank', 'quiz');
|
||||
$errors['name'] = get_string('categorynamecantbeblank', 'question');
|
||||
}
|
||||
|
||||
return $errors;
|
||||
|
@ -1,173 +1,133 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This page prints a particular instance of quiz
|
||||
* This script displays a particular page of a quiz attempt that is in progress.
|
||||
*
|
||||
* @author Martin Dougiamas and many others. This has recently been completely
|
||||
* rewritten by Alex Smith, Julian Sedding and Gustav Delius as part of
|
||||
* the Serving Mathematics project
|
||||
* {@link http://maths.york.ac.uk/serving_maths}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @package quiz
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(dirname(__FILE__) . '/../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
require_once(dirname(__FILE__) . '/../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
||||
/// Look for old-style URLs, such as may be in the logs, and redirect them to startattemtp.php
|
||||
if ($id = optional_param('id', 0, PARAM_INTEGER)) {
|
||||
// Look for old-style URLs, such as may be in the logs, and redirect them to startattemtp.php
|
||||
if ($id = optional_param('id', 0, PARAM_INTEGER)) {
|
||||
redirect($CFG->wwwroot . '/mod/quiz/startattempt.php?cmid=' . $id . '&sesskey=' . sesskey());
|
||||
} else if ($qid = optional_param('q', 0, PARAM_INTEGER)) {
|
||||
} else if ($qid = optional_param('q', 0, PARAM_INTEGER)) {
|
||||
if (!$cm = get_coursemodule_from_instance('quiz', $qid)) {
|
||||
print_error('invalidquizid', 'quiz');
|
||||
}
|
||||
redirect($CFG->wwwroot . '/mod/quiz/startattempt.php?cmid=' . $cm->id . '&sesskey=' . sesskey());
|
||||
}
|
||||
redirect(new moodle_url('/mod/quiz/startattempt.php',
|
||||
array('cmid' => $cm->id, 'sesskey' => sesskey())));
|
||||
}
|
||||
|
||||
/// Get submitted parameters.
|
||||
$attemptid = required_param('attempt', PARAM_INT);
|
||||
$page = optional_param('page', 0, PARAM_INT);
|
||||
// Get submitted parameters.
|
||||
$attemptid = required_param('attempt', PARAM_INT);
|
||||
$page = optional_param('page', 0, PARAM_INT);
|
||||
|
||||
$url = new moodle_url('/mod/quiz/attempt.php', array('attempt' => $attemptid));
|
||||
if ($page !== 0) {
|
||||
$url->param('page', $page);
|
||||
}
|
||||
$PAGE->set_url($url);
|
||||
$attemptobj = quiz_attempt::create($attemptid);
|
||||
$PAGE->set_url($attemptobj->attempt_url(0, $page));
|
||||
|
||||
$attemptobj = quiz_attempt::create($attemptid);
|
||||
// Check login.
|
||||
require_login($attemptobj->get_course(), false, $attemptobj->get_cm());
|
||||
|
||||
/// Check login.
|
||||
require_login($attemptobj->get_course(), false, $attemptobj->get_cm());
|
||||
|
||||
/// Check that this attempt belongs to this user.
|
||||
if ($attemptobj->get_userid() != $USER->id) {
|
||||
// Check that this attempt belongs to this user.
|
||||
if ($attemptobj->get_userid() != $USER->id) {
|
||||
if ($attemptobj->has_capability('mod/quiz:viewreports')) {
|
||||
redirect($attemptobj->review_url(0, $page));
|
||||
} else {
|
||||
quiz_error($attemptobj->get_quiz(), 'notyourattempt');
|
||||
}
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'notyourattempt');
|
||||
}
|
||||
}
|
||||
|
||||
/// Check capabilities and block settings
|
||||
if (!$attemptobj->is_preview_user()) {
|
||||
// Check capabilities and block settings
|
||||
if (!$attemptobj->is_preview_user()) {
|
||||
$attemptobj->require_capability('mod/quiz:attempt');
|
||||
if (empty($attemptobj->get_quiz()->showblocks)) {
|
||||
$PAGE->blocks->show_only_fake_blocks();
|
||||
}
|
||||
|
||||
} else {
|
||||
} else {
|
||||
navigation_node::override_active_url($attemptobj->start_attempt_url());
|
||||
}
|
||||
}
|
||||
|
||||
/// If the attempt is already closed, send them to the review page.
|
||||
if ($attemptobj->is_finished()) {
|
||||
// If the attempt is already closed, send them to the review page.
|
||||
if ($attemptobj->is_finished()) {
|
||||
redirect($attemptobj->review_url(0, $page));
|
||||
}
|
||||
}
|
||||
|
||||
/// Check the access rules.
|
||||
$accessmanager = $attemptobj->get_access_manager(time());
|
||||
$messages = $accessmanager->prevent_access();
|
||||
if (!$attemptobj->is_preview_user() && $messages) {
|
||||
print_error('attempterror', 'quiz', $quizobj->view_url(),
|
||||
$accessmanager->print_messages($messages, true));
|
||||
}
|
||||
$accessmanager->do_password_check($attemptobj->is_preview_user());
|
||||
// Check the access rules.
|
||||
$accessmanager = $attemptobj->get_access_manager(time());
|
||||
$messages = $accessmanager->prevent_access();
|
||||
$output = $PAGE->get_renderer('mod_quiz');
|
||||
if (!$attemptobj->is_preview_user() && $messages) {
|
||||
print_error('attempterror', 'quiz', $attemptobj->view_url(),
|
||||
$output->access_messages($messages));
|
||||
}
|
||||
$accessmanager->do_password_check($attemptobj->is_preview_user());
|
||||
|
||||
add_to_log($attemptobj->get_courseid(), 'quiz', 'continue attempt',
|
||||
add_to_log($attemptobj->get_courseid(), 'quiz', 'continue attempt',
|
||||
'review.php?attempt=' . $attemptobj->get_attemptid(),
|
||||
$attemptobj->get_quizid(), $attemptobj->get_cmid());
|
||||
|
||||
/// Get the list of questions needed by this page.
|
||||
$questionids = $attemptobj->get_question_ids($page);
|
||||
// Get the list of questions needed by this page.
|
||||
$slots = $attemptobj->get_slots($page);
|
||||
|
||||
/// Check.
|
||||
if (empty($questionids)) {
|
||||
quiz_error($quiz, 'noquestionsfound');
|
||||
}
|
||||
// Check.
|
||||
if (empty($slots)) {
|
||||
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'noquestionsfound');
|
||||
}
|
||||
|
||||
/// Load those questions and the associated states.
|
||||
$attemptobj->load_questions($questionids);
|
||||
$attemptobj->load_question_states($questionids);
|
||||
// Initialise the JavaScript.
|
||||
$headtags = $attemptobj->get_html_head_contributions($page);
|
||||
$PAGE->requires->js_init_call('M.mod_quiz.init_attempt_form', null, false, quiz_get_js_module());
|
||||
|
||||
/// Print the quiz page ////////////////////////////////////////////////////////
|
||||
// Arrange for the navigation to be displayed.
|
||||
$navbc = $attemptobj->get_navigation_panel($output, 'quiz_attempt_nav_panel', $page);
|
||||
$firstregion = reset($PAGE->blocks->get_regions());
|
||||
$PAGE->blocks->add_fake_block($navbc, $firstregion);
|
||||
|
||||
// Initialise the JavaScript.
|
||||
$headtags = $attemptobj->get_html_head_contributions($page);
|
||||
$PAGE->requires->js_init_call('M.mod_quiz.init_attempt_form', null, false, quiz_get_js_module());
|
||||
|
||||
// Arrange for the navigation to be displayed.
|
||||
$navbc = $attemptobj->get_navigation_panel('quiz_attempt_nav_panel', $page);
|
||||
$firstregion = reset($PAGE->blocks->get_regions());
|
||||
$PAGE->blocks->add_fake_block($navbc, $firstregion);
|
||||
|
||||
// Print the page header
|
||||
$title = get_string('attempt', 'quiz', $attemptobj->get_attempt_number());
|
||||
$PAGE->set_heading($attemptobj->get_course()->fullname);
|
||||
if ($accessmanager->securewindow_required($attemptobj->is_preview_user())) {
|
||||
$title = get_string('attempt', 'quiz', $attemptobj->get_attempt_number());
|
||||
$headtags = $attemptobj->get_html_head_contributions($page);
|
||||
$PAGE->set_heading($attemptobj->get_course()->fullname);
|
||||
if ($accessmanager->securewindow_required($attemptobj->is_preview_user())) {
|
||||
$accessmanager->setup_secure_page($attemptobj->get_course()->shortname . ': ' .
|
||||
format_string($attemptobj->get_quiz_name()));
|
||||
} else if ($accessmanager->safebrowser_required($attemptobj->is_preview_user())) {
|
||||
$PAGE->set_title($attemptobj->get_course()->shortname . ': '.format_string($attemptobj->get_quiz_name()));
|
||||
|
||||
} else if ($accessmanager->safebrowser_required($attemptobj->is_preview_user())) {
|
||||
$PAGE->set_title($attemptobj->get_course()->shortname . ': ' .
|
||||
format_string($attemptobj->get_quiz_name()));
|
||||
$PAGE->set_cacheable(false);
|
||||
echo $OUTPUT->header();
|
||||
} else {
|
||||
|
||||
} else {
|
||||
$PAGE->set_title(format_string($attemptobj->get_quiz_name()));
|
||||
echo $OUTPUT->header();
|
||||
}
|
||||
}
|
||||
|
||||
if ($attemptobj->is_preview_user()) {
|
||||
|
||||
$quiz = $attemptobj->get_quiz();
|
||||
|
||||
/// Heading and tab bar.
|
||||
echo $OUTPUT->heading(get_string('previewquiz', 'quiz', format_string($quiz->name)));
|
||||
$attemptobj->print_restart_preview_button();
|
||||
|
||||
/// Inform teachers of any restrictions that would apply to students at this point.
|
||||
if ($messages) {
|
||||
echo $OUTPUT->box_start('quizaccessnotices');
|
||||
echo $OUTPUT->heading(get_string('accessnoticesheader', 'quiz'), 3);
|
||||
$accessmanager->print_messages($messages);
|
||||
echo $OUTPUT->box_end();
|
||||
}
|
||||
}
|
||||
|
||||
// Start the form
|
||||
echo '<form id="responseform" method="post" action="', s($attemptobj->processattempt_url()),
|
||||
'" enctype="multipart/form-data" accept-charset="utf-8">', "\n";
|
||||
echo '<div>';
|
||||
|
||||
/// Print all the questions
|
||||
foreach ($attemptobj->get_question_ids($page) as $id) {
|
||||
$attemptobj->print_question($id, false, $attemptobj->attempt_url($id, $page));
|
||||
}
|
||||
|
||||
/// Print a link to the next page.
|
||||
echo '<div class="submitbtns">';
|
||||
if ($attemptobj->is_last_page($page)) {
|
||||
if ($attemptobj->is_last_page($page)) {
|
||||
$nextpage = -1;
|
||||
} else {
|
||||
} else {
|
||||
$nextpage = $page + 1;
|
||||
}
|
||||
echo '<input type="submit" value="' . get_string('next') . '" />';
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
// Some hidden fields to trach what is going on.
|
||||
echo '<input type="hidden" name="attempt" value="' . $attemptobj->get_attemptid() . '" />';
|
||||
echo '<input type="hidden" name="nextpage" id="nextpagehiddeninput" value="' . $nextpage . '" />';
|
||||
echo '<input type="hidden" name="timeup" id="timeup" value="0" />';
|
||||
echo '<input type="hidden" name="sesskey" value="' . sesskey() . '" />';
|
||||
|
||||
// Add a hidden field with questionids. Do this at the end of the form, so
|
||||
// if you navigate before the form has finished loading, it does not wipe all
|
||||
// the student's answers.
|
||||
echo '<input type="hidden" name="questionids" value="' .
|
||||
implode(',', $attemptobj->get_question_ids($page)) . "\" />\n";
|
||||
|
||||
// Finish the form
|
||||
echo '</div>';
|
||||
echo "</form>\n";
|
||||
|
||||
// Finish the page
|
||||
$accessmanager->show_attempt_timer_if_needed($attemptobj->get_attempt(), time());
|
||||
echo $OUTPUT->footer();
|
||||
echo $output->attempt_page($attemptobj, $page, $accessmanager, $messages, $slots, $id, $nextpage);
|
||||
|
||||
$accessmanager->show_attempt_timer_if_needed($attemptobj->get_attempt(), time());
|
||||
echo $OUTPUT->footer();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@ -22,11 +21,18 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/backup/moodle2/backup_quiz_stepslib.php'); // Because it exists (must)
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/backup/moodle2/backup_quiz_stepslib.php');
|
||||
|
||||
|
||||
/**
|
||||
* quiz backup task that provides all the settings and steps to perform one
|
||||
* complete backup of the activity
|
||||
*
|
||||
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class backup_quiz_activity_task extends backup_activity_task {
|
||||
|
||||
@ -64,10 +70,10 @@ class backup_quiz_activity_task extends backup_activity_task {
|
||||
* Code the transformations to perform in the activity in
|
||||
* order to get transportable (encoded) links
|
||||
*/
|
||||
static public function encode_content_links($content) {
|
||||
public static function encode_content_links($content) {
|
||||
global $CFG;
|
||||
|
||||
$base = preg_quote($CFG->wwwroot,"/");
|
||||
$base = preg_quote($CFG->wwwroot, '/');
|
||||
|
||||
// Link to the list of quizzes
|
||||
$search="/(".$base."\/mod\/quiz\/index.php\?id\=)([0-9]+)/";
|
||||
|
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@ -22,12 +21,15 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Define all the backup steps that will be used by the backup_quiz_activity_task
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Define the complete quiz structure for backup, with file and id annotations
|
||||
* Define all the backup steps that will be used by the backup_quiz_activity_task
|
||||
*
|
||||
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class backup_quiz_activity_structure_step extends backup_questions_activity_structure_step {
|
||||
|
||||
@ -39,9 +41,12 @@ class backup_quiz_activity_structure_step extends backup_questions_activity_stru
|
||||
// Define each element separated
|
||||
$quiz = new backup_nested_element('quiz', array('id'), array(
|
||||
'name', 'intro', 'introformat', 'timeopen',
|
||||
'timeclose', 'optionflags', 'penaltyscheme', 'attempts_number',
|
||||
'timeclose', 'preferredbehaviour', 'attempts_number',
|
||||
'attemptonlast', 'grademethod', 'decimalpoints', 'questiondecimalpoints',
|
||||
'review', 'questionsperpage', 'shufflequestions', 'shuffleanswers',
|
||||
'reviewattempt', 'reviewcorrectness', 'reviewmarks',
|
||||
'reviewspecificfeedback', 'reviewgeneralfeedback',
|
||||
'reviewrightanswer', 'reviewoverallfeedback',
|
||||
'questionsperpage', 'shufflequestions', 'shuffleanswers',
|
||||
'questions', 'sumgrades', 'grade', 'timecreated',
|
||||
'timemodified', 'timelimit', 'password', 'subnet',
|
||||
'popup', 'delay1', 'delay2', 'showuserpicture',
|
||||
@ -77,8 +82,7 @@ class backup_quiz_activity_structure_step extends backup_questions_activity_stru
|
||||
|
||||
// This module is using questions, so produce the related question states and sessions
|
||||
// attaching them to the $attempt element based in 'uniqueid' matching
|
||||
$this->add_question_attempts_states($attempt, 'uniqueid');
|
||||
$this->add_question_attempts_sessions($attempt, 'uniqueid');
|
||||
$this->add_question_usages($attempt, 'uniqueid');
|
||||
|
||||
// Build the tree
|
||||
|
||||
@ -100,9 +104,11 @@ class backup_quiz_activity_structure_step extends backup_questions_activity_stru
|
||||
// Define sources
|
||||
$quiz->set_source_table('quiz', array('id' => backup::VAR_ACTIVITYID));
|
||||
|
||||
$qinstance->set_source_table('quiz_question_instances', array('quiz' => backup::VAR_PARENTID));
|
||||
$qinstance->set_source_table('quiz_question_instances',
|
||||
array('quiz' => backup::VAR_PARENTID));
|
||||
|
||||
$feedback->set_source_table('quiz_feedback', array('quizid' => backup::VAR_PARENTID));
|
||||
$feedback->set_source_table('quiz_feedback',
|
||||
array('quizid' => backup::VAR_PARENTID));
|
||||
|
||||
// Quiz overrides to backup are different depending of user info
|
||||
$overrideparams = array('quiz' => backup::VAR_PARENTID);
|
||||
@ -115,7 +121,11 @@ class backup_quiz_activity_structure_step extends backup_questions_activity_stru
|
||||
// All the rest of elements only happen if we are including user info
|
||||
if ($userinfo) {
|
||||
$grade->set_source_table('quiz_grades', array('quiz' => backup::VAR_PARENTID));
|
||||
$attempt->set_source_table('quiz_attempts', array('quiz' => backup::VAR_PARENTID));
|
||||
$attempt->set_source_sql('
|
||||
SELECT *
|
||||
FROM {quiz_attempts}
|
||||
WHERE quiz = :quiz AND preview = 0',
|
||||
array('quiz' => backup::VAR_PARENTID));
|
||||
}
|
||||
|
||||
// Define source alias
|
||||
|
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@ -22,13 +21,19 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/backup/moodle2/restore_quiz_stepslib.php'); // Because it exists (must)
|
||||
require_once($CFG->dirroot . '/mod/quiz/backup/moodle2/restore_quiz_stepslib.php');
|
||||
// Because it exists (must)
|
||||
|
||||
|
||||
/**
|
||||
* quiz restore task that provides all the settings and steps to perform one
|
||||
* complete restore of the activity
|
||||
*
|
||||
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class restore_quiz_activity_task extends restore_activity_task {
|
||||
|
||||
@ -51,11 +56,12 @@ class restore_quiz_activity_task extends restore_activity_task {
|
||||
* Define the contents in the activity that must be
|
||||
* processed by the link decoder
|
||||
*/
|
||||
static public function define_decode_contents() {
|
||||
public static function define_decode_contents() {
|
||||
$contents = array();
|
||||
|
||||
$contents[] = new restore_decode_content('quiz', array('intro'), 'quiz');
|
||||
$contents[] = new restore_decode_content('quiz_feedback', array('feedbacktext'), 'quiz_feedback');
|
||||
$contents[] = new restore_decode_content('quiz_feedback',
|
||||
array('feedbacktext'), 'quiz_feedback');
|
||||
|
||||
return $contents;
|
||||
}
|
||||
@ -64,12 +70,15 @@ class restore_quiz_activity_task extends restore_activity_task {
|
||||
* Define the decoding rules for links belonging
|
||||
* to the activity to be executed by the link decoder
|
||||
*/
|
||||
static public function define_decode_rules() {
|
||||
public static function define_decode_rules() {
|
||||
$rules = array();
|
||||
|
||||
$rules[] = new restore_decode_rule('QUIZVIEWBYID', '/mod/quiz/view.php?id=$1', 'course_module');
|
||||
$rules[] = new restore_decode_rule('QUIZVIEWBYQ', '/mod/quiz/view.php?q=$1', 'quiz');
|
||||
$rules[] = new restore_decode_rule('QUIZINDEX', '/mod/quiz/index.php?id=$1', 'course');
|
||||
$rules[] = new restore_decode_rule('QUIZVIEWBYID',
|
||||
'/mod/quiz/view.php?id=$1', 'course_module');
|
||||
$rules[] = new restore_decode_rule('QUIZVIEWBYQ',
|
||||
'/mod/quiz/view.php?q=$1', 'quiz');
|
||||
$rules[] = new restore_decode_rule('QUIZINDEX',
|
||||
'/mod/quiz/index.php?id=$1', 'course');
|
||||
|
||||
return $rules;
|
||||
|
||||
@ -81,53 +90,79 @@ class restore_quiz_activity_task extends restore_activity_task {
|
||||
* quiz logs. It must return one array
|
||||
* of {@link restore_log_rule} objects
|
||||
*/
|
||||
static public function define_restore_log_rules() {
|
||||
public static function define_restore_log_rules() {
|
||||
$rules = array();
|
||||
|
||||
$rules[] = new restore_log_rule('quiz', 'add', 'view.php?id={course_module}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'update', 'view.php?id={course_module}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'view', 'view.php?id={course_module}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'preview', 'view.php?id={course_module}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'report', 'report.php?id={course_module}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'editquestions', 'view.php?id={course_module}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'delete attempt', 'report.php?id={course_module}', '[oldattempt]');
|
||||
$rules[] = new restore_log_rule('quiz', 'edit override', 'overrideedit.php?id={quiz_override}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'delete override', 'overrides.php.php?cmid={course_module}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'addcategory', 'view.php?id={course_module}', '{question_category}');
|
||||
$rules[] = new restore_log_rule('quiz', 'view summary', 'summary.php?attempt={quiz_attempt_id}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'manualgrade', 'comment.php?attempt={quiz_attempt_id}&question={question}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'manualgrading', 'report.php?mode=grading&q={quiz}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'add',
|
||||
'view.php?id={course_module}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'update',
|
||||
'view.php?id={course_module}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'view',
|
||||
'view.php?id={course_module}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'preview',
|
||||
'view.php?id={course_module}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'report',
|
||||
'report.php?id={course_module}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'editquestions',
|
||||
'view.php?id={course_module}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'delete attempt',
|
||||
'report.php?id={course_module}', '[oldattempt]');
|
||||
$rules[] = new restore_log_rule('quiz', 'edit override',
|
||||
'overrideedit.php?id={quiz_override}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'delete override',
|
||||
'overrides.php.php?cmid={course_module}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'addcategory',
|
||||
'view.php?id={course_module}', '{question_category}');
|
||||
$rules[] = new restore_log_rule('quiz', 'view summary',
|
||||
'summary.php?attempt={quiz_attempt_id}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'manualgrade',
|
||||
'comment.php?attempt={quiz_attempt_id}&question={question}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'manualgrading',
|
||||
'report.php?mode=grading&q={quiz}', '{quiz}');
|
||||
// All the ones calling to review.php have two rules to handle both old and new urls
|
||||
// in any case they are always converted to new urls on restore
|
||||
// TODO: In Moodle 2.x (x >= 5) kill the old rules
|
||||
// Note we are using the 'quiz_attempt_id' mapping becuase that is the one containing the quiz_attempt->ids
|
||||
// old an new for quiz-attempt
|
||||
$rules[] = new restore_log_rule('quiz', 'attempt', 'review.php?id={course_module}&attempt={quiz_attempt}', '{quiz}',
|
||||
// Note we are using the 'quiz_attempt_id' mapping becuase that is the
|
||||
// one containing the quiz_attempt->ids old an new for quiz-attempt
|
||||
$rules[] = new restore_log_rule('quiz', 'attempt',
|
||||
'review.php?id={course_module}&attempt={quiz_attempt}', '{quiz}',
|
||||
null, null, 'review.php?attempt={quiz_attempt}');
|
||||
// old an new for quiz-submit
|
||||
$rules[] = new restore_log_rule('quiz', 'submit', 'review.php?id={course_module}&attempt={quiz_attempt_id}', '{quiz}',
|
||||
$rules[] = new restore_log_rule('quiz', 'submit',
|
||||
'review.php?id={course_module}&attempt={quiz_attempt_id}', '{quiz}',
|
||||
null, null, 'review.php?attempt={quiz_attempt_id}');
|
||||
$rules[] = new restore_log_rule('quiz', 'submit', 'review.php?attempt={quiz_attempt_id}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'submit',
|
||||
'review.php?attempt={quiz_attempt_id}', '{quiz}');
|
||||
// old an new for quiz-review
|
||||
$rules[] = new restore_log_rule('quiz', 'review', 'review.php?id={course_module}&attempt={quiz_attempt_id}', '{quiz}',
|
||||
$rules[] = new restore_log_rule('quiz', 'review',
|
||||
'review.php?id={course_module}&attempt={quiz_attempt_id}', '{quiz}',
|
||||
null, null, 'review.php?attempt={quiz_attempt_id}');
|
||||
$rules[] = new restore_log_rule('quiz', 'review', 'review.php?attempt={quiz_attempt_id}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'review',
|
||||
'review.php?attempt={quiz_attempt_id}', '{quiz}');
|
||||
// old an new for quiz-start attemp
|
||||
$rules[] = new restore_log_rule('quiz', 'start attempt', 'review.php?id={course_module}&attempt={quiz_attempt_id}', '{quiz}',
|
||||
$rules[] = new restore_log_rule('quiz', 'start attempt',
|
||||
'review.php?id={course_module}&attempt={quiz_attempt_id}', '{quiz}',
|
||||
null, null, 'review.php?attempt={quiz_attempt_id}');
|
||||
$rules[] = new restore_log_rule('quiz', 'start attempt', 'review.php?attempt={quiz_attempt_id}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'start attempt',
|
||||
'review.php?attempt={quiz_attempt_id}', '{quiz}');
|
||||
// old an new for quiz-close attemp
|
||||
$rules[] = new restore_log_rule('quiz', 'close attempt', 'review.php?id={course_module}&attempt={quiz_attempt_id}', '{quiz}',
|
||||
$rules[] = new restore_log_rule('quiz', 'close attempt',
|
||||
'review.php?id={course_module}&attempt={quiz_attempt_id}', '{quiz}',
|
||||
null, null, 'review.php?attempt={quiz_attempt_id}');
|
||||
$rules[] = new restore_log_rule('quiz', 'close attempt', 'review.php?attempt={quiz_attempt_id}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'close attempt',
|
||||
'review.php?attempt={quiz_attempt_id}', '{quiz}');
|
||||
// old an new for quiz-continue attempt
|
||||
$rules[] = new restore_log_rule('quiz', 'continue attempt', 'review.php?id={course_module}&attempt={quiz_attempt_id}', '{quiz}',
|
||||
$rules[] = new restore_log_rule('quiz', 'continue attempt',
|
||||
'review.php?id={course_module}&attempt={quiz_attempt_id}', '{quiz}',
|
||||
null, null, 'review.php?attempt={quiz_attempt_id}');
|
||||
$rules[] = new restore_log_rule('quiz', 'continue attempt', 'review.php?attempt={quiz_attempt_id}', '{quiz}');
|
||||
$rules[] = new restore_log_rule('quiz', 'continue attempt',
|
||||
'review.php?attempt={quiz_attempt_id}', '{quiz}');
|
||||
// old an new for quiz-continue attemp
|
||||
$rules[] = new restore_log_rule('quiz', 'continue attemp', 'review.php?id={course_module}&attempt={quiz_attempt_id}', '{quiz}',
|
||||
$rules[] = new restore_log_rule('quiz', 'continue attemp',
|
||||
'review.php?id={course_module}&attempt={quiz_attempt_id}', '{quiz}',
|
||||
null, 'continue attempt', 'review.php?attempt={quiz_attempt_id}');
|
||||
$rules[] = new restore_log_rule('quiz', 'continue attemp', 'review.php?attempt={quiz_attempt_id}', '{quiz}',
|
||||
$rules[] = new restore_log_rule('quiz', 'continue attemp',
|
||||
'review.php?attempt={quiz_attempt_id}', '{quiz}',
|
||||
null, 'continue attempt');
|
||||
|
||||
return $rules;
|
||||
@ -143,7 +178,7 @@ class restore_quiz_activity_task extends restore_activity_task {
|
||||
* by the restore final task, but are defined here at
|
||||
* activity level. All them are rules not linked to any module instance (cmid = 0)
|
||||
*/
|
||||
static public function define_restore_log_rules_for_course() {
|
||||
public static function define_restore_log_rules_for_course() {
|
||||
$rules = array();
|
||||
|
||||
$rules[] = new restore_log_rule('quiz', 'view all', 'index.php?id={course}', null);
|
||||
|
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@ -22,12 +21,15 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Define all the restore steps that will be used by the restore_quiz_activity_task
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Structure step to restore one quiz activity
|
||||
*
|
||||
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class restore_quiz_activity_structure_step extends restore_questions_activity_structure_step {
|
||||
|
||||
@ -37,16 +39,17 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
|
||||
$userinfo = $this->get_setting_value('userinfo');
|
||||
|
||||
$paths[] = new restore_path_element('quiz', '/activity/quiz');
|
||||
$paths[] = new restore_path_element('quiz_question_instance', '/activity/quiz/question_instances/question_instance');
|
||||
$paths[] = new restore_path_element('quiz_question_instance',
|
||||
'/activity/quiz/question_instances/question_instance');
|
||||
$paths[] = new restore_path_element('quiz_feedback', '/activity/quiz/feedbacks/feedback');
|
||||
$paths[] = new restore_path_element('quiz_override', '/activity/quiz/overrides/override');
|
||||
if ($userinfo) {
|
||||
$paths[] = new restore_path_element('quiz_grade', '/activity/quiz/grades/grade');
|
||||
$quizattempt = new restore_path_element('quiz_attempt', '/activity/quiz/attempts/attempt');
|
||||
$quizattempt = new restore_path_element('quiz_attempt',
|
||||
'/activity/quiz/attempts/attempt');
|
||||
$paths[] = $quizattempt;
|
||||
// Add states and sessions
|
||||
$this->add_question_attempts_states($quizattempt, $paths);
|
||||
$this->add_question_attempts_sessions($quizattempt, $paths);
|
||||
$this->add_question_usages($quizattempt, $paths);
|
||||
}
|
||||
|
||||
// Return the paths wrapped into standard activity structure
|
||||
@ -54,7 +57,7 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
|
||||
}
|
||||
|
||||
protected function process_quiz($data) {
|
||||
global $DB;
|
||||
global $CFG, $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
@ -74,6 +77,108 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
|
||||
unset($data->attempts_number);
|
||||
}
|
||||
|
||||
// The old optionflags and penaltyscheme from 2.0 need to be mapped to
|
||||
// the new preferredbehaviour. MDL-20636
|
||||
if (!isset($data->preferredbehaviour)) {
|
||||
if (empty($data->optionflags)) {
|
||||
$data->preferredbehaviour = 'deferredfeedback';
|
||||
} else if (empty($data->penaltyscheme)) {
|
||||
$data->preferredbehaviour = 'adaptivenopenalty';
|
||||
} else {
|
||||
$data->preferredbehaviour = 'adaptive';
|
||||
}
|
||||
unset($data->optionflags);
|
||||
unset($data->penaltyscheme);
|
||||
}
|
||||
|
||||
// The old review column from 2.0 need to be split into the seven new
|
||||
// review columns. MDL-20636
|
||||
if (isset($data->review)) {
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
||||
if (!defined('QUIZ_OLD_IMMEDIATELY')) {
|
||||
define('QUIZ_OLD_IMMEDIATELY', 0x3c003f);
|
||||
define('QUIZ_OLD_OPEN', 0x3c00fc0);
|
||||
define('QUIZ_OLD_CLOSED', 0x3c03f000);
|
||||
|
||||
define('QUIZ_OLD_RESPONSES', 1*0x1041);
|
||||
define('QUIZ_OLD_SCORES', 2*0x1041);
|
||||
define('QUIZ_OLD_FEEDBACK', 4*0x1041);
|
||||
define('QUIZ_OLD_ANSWERS', 8*0x1041);
|
||||
define('QUIZ_OLD_SOLUTIONS', 16*0x1041);
|
||||
define('QUIZ_OLD_GENERALFEEDBACK', 32*0x1041);
|
||||
define('QUIZ_OLD_OVERALLFEEDBACK', 1*0x4440000);
|
||||
}
|
||||
|
||||
$oldreview = $data->review;
|
||||
|
||||
$data->reviewattempt =
|
||||
mod_quiz_display_options::DURING |
|
||||
($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_RESPONSES ?
|
||||
mod_quiz_display_options::IMMEDIATELY_AFTER : 0) |
|
||||
($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_RESPONSES ?
|
||||
mod_quiz_display_options::LATER_WHILE_OPEN : 0) |
|
||||
($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_RESPONSES ?
|
||||
mod_quiz_display_options::AFTER_CLOSE : 0);
|
||||
|
||||
$data->reviewcorrectness =
|
||||
mod_quiz_display_options::DURING |
|
||||
($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_SCORES ?
|
||||
mod_quiz_display_options::IMMEDIATELY_AFTER : 0) |
|
||||
($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_SCORES ?
|
||||
mod_quiz_display_options::LATER_WHILE_OPEN : 0) |
|
||||
($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_SCORES ?
|
||||
mod_quiz_display_options::AFTER_CLOSE : 0);
|
||||
|
||||
$data->reviewmarks =
|
||||
mod_quiz_display_options::DURING |
|
||||
($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_SCORES ?
|
||||
mod_quiz_display_options::IMMEDIATELY_AFTER : 0) |
|
||||
($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_SCORES ?
|
||||
mod_quiz_display_options::LATER_WHILE_OPEN : 0) |
|
||||
($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_SCORES ?
|
||||
mod_quiz_display_options::AFTER_CLOSE : 0);
|
||||
|
||||
$data->reviewspecificfeedback =
|
||||
($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_FEEDBACK ?
|
||||
mod_quiz_display_options::DURING : 0) |
|
||||
($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_FEEDBACK ?
|
||||
mod_quiz_display_options::IMMEDIATELY_AFTER : 0) |
|
||||
($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_FEEDBACK ?
|
||||
mod_quiz_display_options::LATER_WHILE_OPEN : 0) |
|
||||
($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_FEEDBACK ?
|
||||
mod_quiz_display_options::AFTER_CLOSE : 0);
|
||||
|
||||
$data->reviewgeneralfeedback =
|
||||
($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_GENERALFEEDBACK ?
|
||||
mod_quiz_display_options::DURING : 0) |
|
||||
($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_GENERALFEEDBACK ?
|
||||
mod_quiz_display_options::IMMEDIATELY_AFTER : 0) |
|
||||
($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_GENERALFEEDBACK ?
|
||||
mod_quiz_display_options::LATER_WHILE_OPEN : 0) |
|
||||
($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_GENERALFEEDBACK ?
|
||||
mod_quiz_display_options::AFTER_CLOSE : 0);
|
||||
|
||||
$data->reviewrightanswer =
|
||||
($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_ANSWERS ?
|
||||
mod_quiz_display_options::DURING : 0) |
|
||||
($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_ANSWERS ?
|
||||
mod_quiz_display_options::IMMEDIATELY_AFTER : 0) |
|
||||
($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_ANSWERS ?
|
||||
mod_quiz_display_options::LATER_WHILE_OPEN : 0) |
|
||||
($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_ANSWERS ?
|
||||
mod_quiz_display_options::AFTER_CLOSE : 0);
|
||||
|
||||
$data->reviewoverallfeedback =
|
||||
0 |
|
||||
($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_OVERALLFEEDBACK ?
|
||||
mod_quiz_display_options::IMMEDIATELY_AFTER : 0) |
|
||||
($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_OVERALLFEEDBACK ?
|
||||
mod_quiz_display_options::LATER_WHILE_OPEN : 0) |
|
||||
($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_OVERALLFEEDBACK ?
|
||||
mod_quiz_display_options::AFTER_CLOSE : 0);
|
||||
}
|
||||
|
||||
// insert the quiz record
|
||||
$newitemid = $DB->insert_record('quiz', $data);
|
||||
// immediately after inserting "activity" record, call this
|
||||
@ -159,7 +264,7 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
|
||||
$data->quiz = $this->get_new_parentid('quiz');
|
||||
$data->attempt = $data->attemptnum;
|
||||
|
||||
$data->uniqueid = question_new_attempt_uniqueid('quiz');
|
||||
$data->uniqueid = 0; // filled in later by {@link inform_new_usage_id()}
|
||||
|
||||
$data->userid = $this->get_mappingid('user', $data->userid);
|
||||
|
||||
@ -167,18 +272,20 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
|
||||
$data->timefinish = $this->apply_date_offset($data->timefinish);
|
||||
$data->timemodified = $this->apply_date_offset($data->timemodified);
|
||||
|
||||
$data->layout = $this->questions_recode_layout($data->layout);
|
||||
|
||||
$newitemid = $DB->insert_record('quiz_attempts', $data);
|
||||
|
||||
// Save quiz_attempt->uniqueid as quiz_attempt mapping, both question_states and
|
||||
// question_sessions have Fk to it and not to quiz_attempts->id at all.
|
||||
$this->set_mapping('quiz_attempt', $olduniqueid, $data->uniqueid, false);
|
||||
// Also save quiz_attempt->id mapping, because logs use it
|
||||
$this->set_mapping('quiz_attempt_id', $oldid, $newitemid, false);
|
||||
// Save quiz_attempt->id mapping, because logs use it
|
||||
$this->set_mapping('quiz_attempt', $oldid, $newitemid, false);
|
||||
}
|
||||
|
||||
protected function inform_new_usage_id($newusageid) {
|
||||
global $DB;
|
||||
$DB->set_field('quiz_attempts', 'uniqueid', $newusageid, array('id' =>
|
||||
$this->get_new_parentid('quiz_attempt')));
|
||||
}
|
||||
|
||||
protected function after_execute() {
|
||||
parent::after_execute();
|
||||
// Add quiz related files, no need to match by itemname (just internally handled context)
|
||||
$this->add_related_files('mod_quiz', 'intro', null);
|
||||
// Add feedback related files, matching by itemname = 'quiz_feedback'
|
||||
|
@ -1,4 +1,19 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This page allows the teacher to enter a manual grade for a particular question.
|
||||
* This page is expected to only be used in a popup window.
|
||||
@ -6,65 +21,59 @@
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
* @copyright gustav delius 2006
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once('../../config.php');
|
||||
require_once('locallib.php');
|
||||
require_once('../../config.php');
|
||||
require_once('locallib.php');
|
||||
|
||||
$attemptid = required_param('attempt', PARAM_INT); // attempt id
|
||||
$questionid = required_param('question', PARAM_INT); // question id
|
||||
$attemptid = required_param('attempt', PARAM_INT); // attempt id
|
||||
$slot = required_param('slot', PARAM_INT); // question number in attempt
|
||||
|
||||
$PAGE->set_url('/mod/quiz/comment.php', array('attempt'=>$attemptid, 'question'=>$questionid));
|
||||
$PAGE->set_url('/mod/quiz/comment.php', array('attempt' => $attemptid, 'slot' => $slot));
|
||||
|
||||
$attemptobj = quiz_attempt::create($attemptid);
|
||||
$attemptobj = quiz_attempt::create($attemptid);
|
||||
|
||||
/// Can only grade finished attempts.
|
||||
if (!$attemptobj->is_finished()) {
|
||||
// Can only grade finished attempts.
|
||||
if (!$attemptobj->is_finished()) {
|
||||
print_error('attemptclosed', 'quiz');
|
||||
}
|
||||
}
|
||||
|
||||
/// Check login and permissions.
|
||||
require_login($attemptobj->get_courseid(), false, $attemptobj->get_cm());
|
||||
$attemptobj->require_capability('mod/quiz:grade');
|
||||
// Check login and permissions.
|
||||
require_login($attemptobj->get_courseid(), false, $attemptobj->get_cm());
|
||||
$attemptobj->require_capability('mod/quiz:grade');
|
||||
|
||||
/// Load the questions and states.
|
||||
$questionids = array($questionid);
|
||||
$attemptobj->load_questions($questionids);
|
||||
$attemptobj->load_question_states($questionids);
|
||||
|
||||
/// Log this action.
|
||||
add_to_log($attemptobj->get_courseid(), 'quiz', 'manualgrade', 'comment.php?attempt=' .
|
||||
$attemptobj->get_attemptid() . '&question=' . $questionid,
|
||||
// Log this action.
|
||||
add_to_log($attemptobj->get_courseid(), 'quiz', 'manualgrade', 'comment.php?attempt=' .
|
||||
$attemptobj->get_attemptid() . '&slot=' . $slot,
|
||||
$attemptobj->get_quizid(), $attemptobj->get_cmid());
|
||||
|
||||
/// Print the page header
|
||||
$PAGE->set_pagelayout('popup');
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(format_string($attemptobj->get_question($questionid)->name));
|
||||
// Print the page header
|
||||
$PAGE->set_pagelayout('popup');
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(format_string($attemptobj->get_question_name($slot)));
|
||||
|
||||
/// Process any data that was submitted.
|
||||
if ($data = data_submitted() and confirm_sesskey()) {
|
||||
$error = $attemptobj->process_comment($questionid,
|
||||
$data->response['comment'], FORMAT_HTML, $data->response['grade']);
|
||||
|
||||
/// If success, notify and print a close button.
|
||||
if (!is_string($error)) {
|
||||
// Process any data that was submitted.
|
||||
if (data_submitted() && confirm_sesskey()) {
|
||||
if (optional_param('submit', false, PARAM_BOOL)) {
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
$attemptobj->process_all_actions(time());
|
||||
$transaction->allow_commit();
|
||||
echo $OUTPUT->notification(get_string('changessaved'), 'notifysuccess');
|
||||
close_window(2, true);
|
||||
die;
|
||||
}
|
||||
}
|
||||
|
||||
/// Otherwise, display the error and fall throug to re-display the form.
|
||||
echo $OUTPUT->notification($error);
|
||||
}
|
||||
|
||||
/// Print the comment form.
|
||||
echo '<form method="post" class="mform" id="manualgradingform" action="' . $CFG->wwwroot . '/mod/quiz/comment.php">';
|
||||
$attemptobj->question_print_comment_fields($questionid, 'response');
|
||||
// Print the comment form.
|
||||
echo '<form method="post" class="mform" id="manualgradingform" action="' .
|
||||
$CFG->wwwroot . '/mod/quiz/comment.php">';
|
||||
echo $attemptobj->render_question_for_commenting($slot);
|
||||
?>
|
||||
<div>
|
||||
<input type="hidden" name="attempt" value="<?php echo $attemptobj->get_attemptid(); ?>" />
|
||||
<input type="hidden" name="question" value="<?php echo $questionid; ?>" />
|
||||
<input type="hidden" name="slot" value="<?php echo $slot; ?>" />
|
||||
<input type="hidden" name="slots" value="<?php echo $slot; ?>" />
|
||||
<input type="hidden" name="sesskey" value="<?php echo sesskey(); ?>" />
|
||||
</div>
|
||||
<fieldset class="hidden">
|
||||
@ -74,15 +83,16 @@
|
||||
<div class="fgrouplabel"><label> </label></div>
|
||||
</div>
|
||||
<fieldset class="felement fgroup">
|
||||
<input id="id_submitbutton" type="submit" name="submit" value="<?php print_string('save', 'quiz'); ?>"/>
|
||||
<input id="id_cancel" type="button" value="<?php print_string('cancel'); ?>" onclick="close_window"/>
|
||||
<input id="id_submitbutton" type="submit" name="submit" value="<?php
|
||||
print_string('save', 'quiz'); ?>"/>
|
||||
<input id="id_cancel" type="button" value="<?php
|
||||
print_string('cancel'); ?>" onclick="close_window()"/>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<?php
|
||||
echo '</form>';
|
||||
echo '</form>';
|
||||
|
||||
/// End of the page.
|
||||
echo $OUTPUT->footer();
|
||||
?>
|
||||
// End of the page.
|
||||
echo $OUTPUT->footer();
|
||||
|
@ -1,9 +1,30 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Capability definitions for the quiz module.
|
||||
*
|
||||
* For naming conventions, see lib/db/access.php.
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
* @copyright 2006 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$capabilities = array(
|
||||
|
||||
// Ability to see that the quiz exists, and the basic information
|
||||
|
@ -1,26 +1,50 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// This file replaces:
|
||||
// * STATEMENTS section in db/install.xml
|
||||
// * lib.php/modulename_install() post installation hook
|
||||
// * partially defaults.php
|
||||
/**
|
||||
* Post-install code for the quiz module.
|
||||
*
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
* @copyright 2009 Petr Skoda
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Code run after the quiz module database tables have been created.
|
||||
*/
|
||||
function xmldb_quiz_install() {
|
||||
global $DB;
|
||||
|
||||
$record = new stdClass();
|
||||
$record->name = 'overview';
|
||||
$record->displayorder = '10000';
|
||||
$DB->insert_record('quiz_report', $record);
|
||||
$DB->insert_record('quiz_reports', $record);
|
||||
|
||||
$record = new stdClass();
|
||||
$record->name = 'responses';
|
||||
$record->displayorder = '9000';
|
||||
$DB->insert_record('quiz_report', $record);
|
||||
$DB->insert_record('quiz_reports', $record);
|
||||
|
||||
$record = new stdClass();
|
||||
$record->name = 'grading';
|
||||
$record->displayorder = '6000';
|
||||
$DB->insert_record('quiz_report', $record);
|
||||
|
||||
$DB->insert_record('quiz_reports', $record);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="mod/quiz/db" VERSION="20100722" COMMENT="XMLDB file for Moodle mod/quiz"
|
||||
<XMLDB PATH="mod/quiz/db" VERSION="20110512" COMMENT="XMLDB file for Moodle mod/quiz"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
@ -7,34 +7,39 @@
|
||||
<TABLE NAME="quiz" COMMENT="Main information about each quiz" NEXT="quiz_attempts">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="course"/>
|
||||
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Foreign key references course.id." PREVIOUS="id" NEXT="name"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="The name of this quiz." PREVIOUS="course" NEXT="intro"/>
|
||||
<FIELD NAME="intro" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="The introductory text desplayed on the view.php page." PREVIOUS="name" NEXT="introformat"/>
|
||||
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="name"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="course" NEXT="intro"/>
|
||||
<FIELD NAME="intro" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="name" NEXT="introformat"/>
|
||||
<FIELD NAME="introformat" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="intro" NEXT="timeopen"/>
|
||||
<FIELD NAME="timeopen" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Time at which students may start attempting this quiz." PREVIOUS="introformat" NEXT="timeclose"/>
|
||||
<FIELD NAME="timeclose" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Time by which students must have completed their attempt." PREVIOUS="timeopen" NEXT="optionflags"/>
|
||||
<FIELD NAME="optionflags" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="This stores the adaptive mode setting for this quiz." PREVIOUS="timeclose" NEXT="penaltyscheme"/>
|
||||
<FIELD NAME="penaltyscheme" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Stores the apply penaties setting." PREVIOUS="optionflags" NEXT="attempts"/>
|
||||
<FIELD NAME="attempts" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="The maximum number of attempts that a student is allowed at this quiz. 0 mean no limit." PREVIOUS="penaltyscheme" NEXT="attemptonlast"/>
|
||||
<FIELD NAME="attemptonlast" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="Whether each attempt builds on last mode is on." PREVIOUS="attempts" NEXT="grademethod"/>
|
||||
<FIELD NAME="grademethod" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" COMMENT="How individual attempt grades are combined to get the overall grade. From the top of mod/quiz/lib.php: 1 = QUIZ_GRADEHIGHEST, 2 = QUIZ_GRADEAVERAGE, 3 = QUIZ_ATTEMPTFIRST, 4 = QUIZ_ATTEMPTLAST." PREVIOUS="attemptonlast" NEXT="decimalpoints"/>
|
||||
<FIELD NAME="decimalpoints" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="2" SEQUENCE="false" COMMENT="Number of decimal points to display when printing scores belonging to this quiz." PREVIOUS="grademethod" NEXT="questiondecimalpoints"/>
|
||||
<FIELD NAME="questiondecimalpoints" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="-2" SEQUENCE="false" COMMENT="The number of decimal digits to use when displaying question grades. -1 = use decimalpoints, otherwise a separate setting." PREVIOUS="decimalpoints" NEXT="review"/>
|
||||
<FIELD NAME="review" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="A bitfield encoding the Review options setting. Read the code of function quiz_get_reviewoptions from mod/quiz/locallib.php to see what each bit means." PREVIOUS="questiondecimalpoints" NEXT="questionsperpage"/>
|
||||
<FIELD NAME="questionsperpage" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="This does not do exactly what the name suggests, and the behaviour depends on the shufflequestions setting." PREVIOUS="review" NEXT="shufflequestions"/>
|
||||
<FIELD NAME="shufflequestions" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="Whether the list of questions in the quiz should be randomly shuffled at the start of each attempt." PREVIOUS="questionsperpage" NEXT="shuffleanswers"/>
|
||||
<FIELD NAME="shuffleanswers" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="Whether, in question types that support it, individual parts of a question should be shuffled." PREVIOUS="shufflequestions" NEXT="questions"/>
|
||||
<FIELD NAME="questions" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="Comma-separated list of questionids, with 0s for page breaks. The layout of questions in this quiz." PREVIOUS="shuffleanswers" NEXT="sumgrades"/>
|
||||
<FIELD NAME="sumgrades" TYPE="number" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" DECIMALS="5" COMMENT="Total of the maximum grades you can get from each question. This is redundant, it is SELECT SUM(grade) FROM {quiz_question_instances} WHERE quiz = ?." PREVIOUS="questions" NEXT="grade"/>
|
||||
<FIELD NAME="grade" TYPE="number" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" DECIMALS="5" COMMENT="Maximum grade that you can get from this quiz." PREVIOUS="sumgrades" NEXT="timecreated"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Timestamp when this quiz was created." PREVIOUS="grade" NEXT="timemodified"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Timestamp when this row was last updated." PREVIOUS="timecreated" NEXT="timelimit"/>
|
||||
<FIELD NAME="timelimit" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Time limit in seconds." PREVIOUS="timemodified" NEXT="password"/>
|
||||
<FIELD NAME="password" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="Students must enter this password before they can attempt the quiz." PREVIOUS="timelimit" NEXT="subnet"/>
|
||||
<FIELD NAME="subnet" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" COMMENT="If set, only allow attempts from certain IP addresses. The checking is performed by the address_in_subnet function from lib/moodlelib.php." PREVIOUS="password" NEXT="popup"/>
|
||||
<FIELD NAME="popup" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="Force the quiz to be attempted in a full-screen pop-up window with some evil JavaScript that attempts to prevent copying and pasting, etc." PREVIOUS="subnet" NEXT="delay1"/>
|
||||
<FIELD NAME="delay1" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="Enforced delay between the first and second attempts, in seconds." PREVIOUS="popup" NEXT="delay2"/>
|
||||
<FIELD NAME="delay2" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="Enforced delay between the second and subsequent attempts, in seconds." PREVIOUS="delay1" NEXT="showuserpicture"/>
|
||||
<FIELD NAME="timeopen" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="introformat" NEXT="timeclose"/>
|
||||
<FIELD NAME="timeclose" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timeopen" NEXT="preferredbehaviour"/>
|
||||
<FIELD NAME="preferredbehaviour" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" PREVIOUS="timeclose" NEXT="attempts"/>
|
||||
<FIELD NAME="attempts" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="preferredbehaviour" NEXT="attemptonlast"/>
|
||||
<FIELD NAME="attemptonlast" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="attempts" NEXT="grademethod"/>
|
||||
<FIELD NAME="grademethod" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" PREVIOUS="attemptonlast" NEXT="decimalpoints"/>
|
||||
<FIELD NAME="decimalpoints" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="2" SEQUENCE="false" PREVIOUS="grademethod" NEXT="questiondecimalpoints"/>
|
||||
<FIELD NAME="questiondecimalpoints" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="-2" SEQUENCE="false" PREVIOUS="decimalpoints" NEXT="reviewattempt"/>
|
||||
<FIELD NAME="reviewattempt" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether users are allowed to review their quiz attempts at various times. This is a bit field, decoded by the mod_quiz_display_options class. It is formed by ORing together the constants defined there." PREVIOUS="questiondecimalpoints" NEXT="reviewcorrectness"/>
|
||||
<FIELD NAME="reviewcorrectness" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether users are allowed to review their quiz attempts at various times. A bit field, like reviewattempt." PREVIOUS="reviewattempt" NEXT="reviewmarks"/>
|
||||
<FIELD NAME="reviewmarks" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether users are allowed to review their quiz attempts at various times. A bit field, like reviewattempt." PREVIOUS="reviewcorrectness" NEXT="reviewspecificfeedback"/>
|
||||
<FIELD NAME="reviewspecificfeedback" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether users are allowed to review their quiz attempts at various times. A bit field, like reviewattempt." PREVIOUS="reviewmarks" NEXT="reviewgeneralfeedback"/>
|
||||
<FIELD NAME="reviewgeneralfeedback" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether users are allowed to review their quiz attempts at various times. A bit field, like reviewattempt." PREVIOUS="reviewspecificfeedback" NEXT="reviewrightanswer"/>
|
||||
<FIELD NAME="reviewrightanswer" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether users are allowed to review their quiz attempts at various times. A bit field, like reviewattempt." PREVIOUS="reviewgeneralfeedback" NEXT="reviewoverallfeedback"/>
|
||||
<FIELD NAME="reviewoverallfeedback" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether users are allowed to review their quiz attempts at various times. A bit field, like reviewattempt." PREVIOUS="reviewrightanswer" NEXT="questionsperpage"/>
|
||||
<FIELD NAME="questionsperpage" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="reviewoverallfeedback" NEXT="shufflequestions"/>
|
||||
<FIELD NAME="shufflequestions" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="questionsperpage" NEXT="shuffleanswers"/>
|
||||
<FIELD NAME="shuffleanswers" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="shufflequestions" NEXT="questions"/>
|
||||
<FIELD NAME="questions" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="shuffleanswers" NEXT="sumgrades"/>
|
||||
<FIELD NAME="sumgrades" TYPE="number" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" DECIMALS="5" PREVIOUS="questions" NEXT="grade"/>
|
||||
<FIELD NAME="grade" TYPE="number" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" DECIMALS="5" PREVIOUS="sumgrades" NEXT="timecreated"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="grade" NEXT="timemodified"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timecreated" NEXT="timelimit"/>
|
||||
<FIELD NAME="timelimit" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timemodified" NEXT="password"/>
|
||||
<FIELD NAME="password" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="timelimit" NEXT="subnet"/>
|
||||
<FIELD NAME="subnet" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="password" NEXT="popup"/>
|
||||
<FIELD NAME="popup" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="subnet" NEXT="delay1"/>
|
||||
<FIELD NAME="delay1" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="popup" NEXT="delay2"/>
|
||||
<FIELD NAME="delay2" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="delay1" NEXT="showuserpicture"/>
|
||||
<FIELD NAME="showuserpicture" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="Option to show the user's picture during the attempt and on the review page." PREVIOUS="delay2" NEXT="showblocks"/>
|
||||
<FIELD NAME="showblocks" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="Whether blocks should be shown on the attempt.php and review.php pages." PREVIOUS="showuserpicture"/>
|
||||
</FIELDS>
|
||||
@ -48,16 +53,17 @@
|
||||
<TABLE NAME="quiz_attempts" COMMENT="Stores various attempts on a quiz" PREVIOUS="quiz" NEXT="quiz_grades">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="uniqueid"/>
|
||||
<FIELD NAME="uniqueid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Foreign key references question_attempts.id, and hence links into the attempt information for each question in the attempt." PREVIOUS="id" NEXT="quiz"/>
|
||||
<FIELD NAME="quiz" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Foreign key references quiz.id." PREVIOUS="uniqueid" NEXT="userid"/>
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Foreign key references user.id." PREVIOUS="quiz" NEXT="attempt"/>
|
||||
<FIELD NAME="attempt" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" COMMENT="The attempt number for this user on this quiz. It counts up from one. (quiz, userid, attempt) could be an alternate primary key for this table." PREVIOUS="userid" NEXT="sumgrades"/>
|
||||
<FIELD NAME="sumgrades" TYPE="number" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" DECIMALS="5" COMMENT="The sum of the user's grades for all questions in this attempt." PREVIOUS="attempt" NEXT="timestart"/>
|
||||
<FIELD NAME="timestart" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="The time this attempt started." PREVIOUS="sumgrades" NEXT="timefinish"/>
|
||||
<FIELD NAME="timefinish" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="The time this attempt finished. If 0, this attempt is still open." PREVIOUS="timestart" NEXT="timemodified"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="The time this attemtp was last modified. I think this is not changed by a regrade, and I don't know about what happens if a teacher manually grades a question. If you really need to know, look at the code, then update this comment. Thanks." PREVIOUS="timefinish" NEXT="layout"/>
|
||||
<FIELD NAME="layout" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" COMMENT="A comma-separated list of question ids, with 0s for page breaks. If quiz.shuffequestions = 0, this will be the same as quiz.layout." PREVIOUS="timemodified" NEXT="preview"/>
|
||||
<FIELD NAME="preview" TYPE="int" LENGTH="3" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Used to distinguish preview attempts. Previews do not show up in reports; are deleted automatically when quiz settings are changed; and do not prevent the quiz from being edited." PREVIOUS="layout"/>
|
||||
<FIELD NAME="uniqueid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="quiz"/>
|
||||
<FIELD NAME="quiz" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="uniqueid" NEXT="userid"/>
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="quiz" NEXT="attempt"/>
|
||||
<FIELD NAME="attempt" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" PREVIOUS="userid" NEXT="sumgrades"/>
|
||||
<FIELD NAME="sumgrades" TYPE="number" LENGTH="10" NOTNULL="false" UNSIGNED="false" SEQUENCE="false" DECIMALS="5" PREVIOUS="attempt" NEXT="timestart"/>
|
||||
<FIELD NAME="timestart" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="sumgrades" NEXT="timefinish"/>
|
||||
<FIELD NAME="timefinish" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timestart" NEXT="timemodified"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timefinish" NEXT="layout"/>
|
||||
<FIELD NAME="layout" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="timemodified" NEXT="preview"/>
|
||||
<FIELD NAME="preview" TYPE="int" LENGTH="3" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="layout" NEXT="needsupgradetonewqe"/>
|
||||
<FIELD NAME="needsupgradetonewqe" TYPE="int" LENGTH="3" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="preview"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="uniqueid"/>
|
||||
@ -97,7 +103,7 @@
|
||||
<KEY NAME="question" TYPE="foreign" FIELDS="question" REFTABLE="question" REFFIELDS="id" PREVIOUS="quiz"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="quiz_feedback" COMMENT="Feedback given to students based on which grade band their overall score lies." PREVIOUS="quiz_question_instances" NEXT="quiz_report">
|
||||
<TABLE NAME="quiz_feedback" COMMENT="Feedback given to students based on which grade band their overall score lies." PREVIOUS="quiz_question_instances" NEXT="quiz_overrides">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="quizid"/>
|
||||
<FIELD NAME="quizid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Foreign key references quiz.id." PREVIOUS="id" NEXT="feedbacktext"/>
|
||||
@ -111,20 +117,7 @@
|
||||
<KEY NAME="quizid" TYPE="foreign" FIELDS="quizid" REFTABLE="quiz" REFFIELDS="id" PREVIOUS="primary"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="quiz_report" COMMENT="Lists all the installed quiz reports and their display order and so on. No need to worry about deleting old records. Only records with an equivalent directory are displayed." PREVIOUS="quiz_feedback" NEXT="quiz_overrides">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="name"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="name of the report, same as the directory name" PREVIOUS="id" NEXT="displayorder"/>
|
||||
<FIELD NAME="displayorder" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="display order for report tabs" PREVIOUS="name" NEXT="lastcron"/>
|
||||
<FIELD NAME="lastcron" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="timestamp when cron was last run for this report." PREVIOUS="displayorder" NEXT="cron"/>
|
||||
<FIELD NAME="cron" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="0 if there is no cron for this report (default) or the time between crons otherwise." PREVIOUS="lastcron" NEXT="capability"/>
|
||||
<FIELD NAME="capability" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="Capability required to see this report. May be blank which means use the default of mod/quiz:viewreport. This is used when deciding which tabs to render." PREVIOUS="cron"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="quiz_overrides" COMMENT="The overrides to quiz settings on a per-user and per-group basis." PREVIOUS="quiz_report">
|
||||
<TABLE NAME="quiz_overrides" COMMENT="The overrides to quiz settings on a per-user and per-group basis." PREVIOUS="quiz_feedback" NEXT="quiz_reports">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="quiz"/>
|
||||
<FIELD NAME="quiz" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="Foreign key references quiz.id" PREVIOUS="id" NEXT="groupid"/>
|
||||
@ -143,5 +136,21 @@
|
||||
<KEY NAME="userid" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id" PREVIOUS="groupid"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="quiz_reports" COMMENT="Lists all the installed quiz reports and their display order and so on. No need to worry about deleting old records. Only records with an equivalent directory are displayed." PREVIOUS="quiz_overrides">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" NEXT="name"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="name of the report, same as the directory name" PREVIOUS="id" NEXT="displayorder"/>
|
||||
<FIELD NAME="displayorder" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="false" COMMENT="display order for report tabs" PREVIOUS="name" NEXT="lastcron"/>
|
||||
<FIELD NAME="lastcron" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="timestamp when cron was last run for this report." PREVIOUS="displayorder" NEXT="cron"/>
|
||||
<FIELD NAME="cron" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" COMMENT="0 if there is no cron for this report (default) or the time between crons otherwise." PREVIOUS="lastcron" NEXT="capability"/>
|
||||
<FIELD NAME="capability" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="Capability required to see this report. May be blank which means use the default of mod/quiz:viewreport. This is used when deciding which tabs to render." PREVIOUS="cron"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="name" UNIQUE="true" FIELDS="name"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
</TABLES>
|
||||
</XMLDB>
|
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@ -16,7 +15,7 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Definition of log events
|
||||
* Definition of log events for the quiz module.
|
||||
*
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
|
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@ -16,26 +15,24 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Defines message providers (types of messages being sent)
|
||||
* Defines message providers (types of message sent) for the quiz module.
|
||||
*
|
||||
* @package mod-quiz
|
||||
* @copyright 2010 onwards Andrew Davis http://moodle.com
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
* @copyright 2010 Andrew Davis http://moodle.com
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$messageproviders = array (
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
// notify teacher that a student has submitted a quiz attempt
|
||||
$messageproviders = array (
|
||||
// Notify teacher that a student has submitted a quiz attempt
|
||||
'submission' => array (
|
||||
'capability' => 'mod/quiz:emailnotifysubmission'
|
||||
),
|
||||
|
||||
// confirm a student's quiz attempt
|
||||
// Confirm a student's quiz attempt
|
||||
'confirmation' => array (
|
||||
'capability' => 'mod/quiz:emailconfirmsubmission'
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
@ -1,3 +1,28 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$subplugins = array('quiz'=>'mod/quiz/report');
|
||||
/**
|
||||
* Sub-plugin definitions for the quiz module.
|
||||
*
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
* @copyright 2010 Petr Skoda
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$subplugins = array('quiz' => 'mod/quiz/report');
|
||||
|
File diff suppressed because it is too large
Load Diff
76
mod/quiz/db/upgradelib.php
Normal file
76
mod/quiz/db/upgradelib.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Upgrade helper code for the quiz module.
|
||||
*
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
* @copyright 2006 Eloy Lafuente (stronk7)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Upgrade states for an attempt to Moodle 1.5 model
|
||||
*
|
||||
* Any state that does not yet have its timestamp set to nonzero has not yet been
|
||||
* upgraded from Moodle 1.4. The reason these are still around is that for large
|
||||
* sites it would have taken too long to upgrade all states at once. This function
|
||||
* sets the timestamp field and creates an entry in the question_sessions table.
|
||||
* @param object $attempt The attempt whose states need upgrading
|
||||
*/
|
||||
function quiz_upgrade_very_old_question_sessions($attempt) {
|
||||
global $DB;
|
||||
// The old quiz model only allowed a single response per quiz attempt so that there will be
|
||||
// only one state record per question for this attempt.
|
||||
|
||||
// We set the timestamp of all states to the timemodified field of the attempt.
|
||||
$DB->execute("UPDATE {question_states} SET timestamp = ? WHERE attempt = ?",
|
||||
array($attempt->timemodified, $attempt->uniqueid));
|
||||
|
||||
// For each state we create an entry in the question_sessions table, with both newest and
|
||||
// newgraded pointing to this state.
|
||||
// Actually we only do this for states whose question is actually listed in $attempt->layout.
|
||||
// We do not do it for states associated to wrapped questions like for example the questions
|
||||
// used by a RANDOM question
|
||||
$session = new stdClass();
|
||||
$session->attemptid = $attempt->uniqueid;
|
||||
$session->sumpenalty = 0;
|
||||
$session->manualcomment = '';
|
||||
$session->manualcommentformat = FORMAT_HTML;
|
||||
$session->flagged = 0;
|
||||
|
||||
$questionlist = str_replace(',0', '', quiz_clean_layout($layout, true));
|
||||
if (!$questionlist) {
|
||||
return;
|
||||
}
|
||||
list($usql, $question_params) = $DB->get_in_or_equal(explode(',', $questionlist));
|
||||
$params = array_merge(array($attempt->uniqueid), $question_params);
|
||||
|
||||
if ($states = $DB->get_records_select('question_states',
|
||||
"attempt = ? AND question $usql", $params)) {
|
||||
foreach ($states as $state) {
|
||||
$session->newgraded = $state->id;
|
||||
$session->newest = $state->id;
|
||||
$session->questionid = $state->question;
|
||||
$DB->insert_record('question_sessions', $session, false);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,40 @@
|
||||
/** JavaScript for /mod/quiz/edit.php */
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* JavaScript library for the quiz module editing interface.
|
||||
*
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
* @copyright 2008 Olli Savolainen
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
// Initialise everything on the quiz edit/order and paging page.
|
||||
var quiz_edit = {};
|
||||
function quiz_edit_init() {
|
||||
function quiz_edit_init(Y) {
|
||||
M.core_scroll_manager.scroll_to_saved_pos(Y);
|
||||
Y.on('submit', function(e) {
|
||||
M.core_scroll_manager.save_scroll_pos(Y, 'id_existingcategory');
|
||||
}, '#mform1');
|
||||
Y.on('submit', function(e) {
|
||||
M.core_scroll_manager.save_scroll_pos(Y, e.target.get('firstChild'));
|
||||
}, '.quizsavegradesform');
|
||||
|
||||
// Add random question dialogue --------------------------------------------
|
||||
|
||||
var randomquestiondialog = YAHOO.util.Dom.get('randomquestiondialog');
|
||||
if (randomquestiondialog) {
|
||||
YAHOO.util.Dom.get(document.body).appendChild(randomquestiondialog);
|
||||
@ -125,15 +154,3 @@ function quiz_settings_init() {
|
||||
}, 50);
|
||||
});
|
||||
}
|
||||
|
||||
// Depending on which page this is, do the appropriate initialisation.
|
||||
function quiz_edit_generic_init() {
|
||||
switch (document.body.id) {
|
||||
case 'page-mod-quiz-edit':
|
||||
quiz_edit_init();
|
||||
break;
|
||||
case 'page-mod-quiz-mod':
|
||||
quiz_settings_init();
|
||||
}
|
||||
}
|
||||
YAHOO.util.Event.onDOMReady(quiz_edit_generic_init);
|
||||
|
@ -1,27 +1,19 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// NOTICE OF COPYRIGHT //
|
||||
// //
|
||||
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
|
||||
// http://moodle.org //
|
||||
// //
|
||||
// Copyright (C) 1999 onwards Martin Dougiamas and others //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details: //
|
||||
// //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Page to edit quizzes
|
||||
@ -43,15 +35,19 @@
|
||||
* delete Removes a question from the quiz
|
||||
* savechanges Saves the order and grades for questions in the quiz
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @package quiz
|
||||
*//** */
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
* @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
require_once('../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/editlib.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/addrandomform.php');
|
||||
require_once($CFG->dirroot . '/question/category_class.php');
|
||||
|
||||
|
||||
/**
|
||||
* Callback function called from question_list() function
|
||||
* (which is called from showbank())
|
||||
@ -64,8 +60,8 @@ function module_specific_buttons($cmid, $cmoptions) {
|
||||
} else {
|
||||
$disabled = '';
|
||||
}
|
||||
$out = '<input type="submit" name="add" value="' . $OUTPUT->larrow() . ' ' . get_string('addtoquiz', 'quiz') .
|
||||
'" ' . $disabled . "/>\n";
|
||||
$out = '<input type="submit" name="add" value="' . $OUTPUT->larrow() . ' ' .
|
||||
get_string('addtoquiz', 'quiz') . '" ' . $disabled . "/>\n";
|
||||
return $out;
|
||||
}
|
||||
|
||||
@ -74,7 +70,7 @@ function module_specific_buttons($cmid, $cmoptions) {
|
||||
* (which is called from showbank())
|
||||
*/
|
||||
function module_specific_controls($totalnumber, $recurse, $category, $cmid, $cmoptions) {
|
||||
global $QTYPES, $OUTPUT;
|
||||
global $OUTPUT;
|
||||
$out = '';
|
||||
$catcontext = get_context_instance_by_id($category->contextid);
|
||||
if (has_capability('moodle/question:useall', $catcontext)) {
|
||||
@ -84,7 +80,8 @@ function module_specific_controls($totalnumber, $recurse, $category, $cmid, $cmo
|
||||
$disabled = '';
|
||||
}
|
||||
$randomusablequestions =
|
||||
$QTYPES['random']->get_usable_questions_from_category($category->id, $recurse, '0');
|
||||
question_bank::get_qtype('random')->get_available_questions_from_category(
|
||||
$category->id, $recurse);
|
||||
$maxrand = count($randomusablequestions);
|
||||
if ($maxrand > 0) {
|
||||
for ($i = 1; $i <= min(10, $maxrand); $i++) {
|
||||
@ -117,9 +114,11 @@ function module_specific_controls($totalnumber, $recurse, $category, $cmid, $cmo
|
||||
//this page otherwise they would go in question_edit_setup
|
||||
$quiz_reordertool = optional_param('reordertool', -1, PARAM_BOOL);
|
||||
$quiz_qbanktool = optional_param('qbanktool', -1, PARAM_BOOL);
|
||||
$scrollpos = optional_param('scrollpos', '', PARAM_INT);
|
||||
|
||||
list($thispageurl, $contexts, $cmid, $cm, $quiz, $pagevars) =
|
||||
question_edit_setup('editq', '/mod/quiz/edit.php', true);
|
||||
$quiz->questions = quiz_clean_layout($quiz->questions);
|
||||
|
||||
$defaultcategoryobj = question_make_default_categories($contexts->all());
|
||||
$defaultcategory = $defaultcategoryobj->id . ',' . $defaultcategoryobj->contextid;
|
||||
@ -154,7 +153,7 @@ if (!$course) {
|
||||
print_error('invalidcourseid', 'error');
|
||||
}
|
||||
|
||||
$questionbank = new quiz_question_bank_view($contexts, $thispageurl, $course, $cm);
|
||||
$questionbank = new quiz_question_bank_view($contexts, $thispageurl, $course, $cm, $quiz);
|
||||
$questionbank->set_quiz_has_attempts($quizhasattempts);
|
||||
|
||||
// Log this visit.
|
||||
@ -164,7 +163,7 @@ add_to_log($cm->course, 'quiz', 'editquestions',
|
||||
// You need mod/quiz:manage in addition to question capabilities to access this page.
|
||||
require_capability('mod/quiz:manage', $contexts->lowest());
|
||||
|
||||
if (empty($quiz->grades)) { // Construct an array to hold all the grades.
|
||||
if (empty($quiz->grades)) {
|
||||
$quiz->grades = quiz_get_all_question_grades($quiz);
|
||||
}
|
||||
|
||||
@ -184,37 +183,45 @@ foreach ($params as $key => $value) {
|
||||
}
|
||||
}
|
||||
|
||||
$afteractionurl = new moodle_url($thispageurl);
|
||||
if ($scrollpos) {
|
||||
$afteractionurl->param('scrollpos', $scrollpos);
|
||||
}
|
||||
if (($up = optional_param('up', false, PARAM_INT)) && confirm_sesskey()) {
|
||||
$quiz->questions = quiz_move_question_up($quiz->questions, $up);
|
||||
quiz_save_new_layout($quiz);
|
||||
redirect($thispageurl);
|
||||
$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
|
||||
quiz_delete_previews($quiz);
|
||||
redirect($afteractionurl);
|
||||
}
|
||||
|
||||
if (($down = optional_param('down', false, PARAM_INT)) && confirm_sesskey()) {
|
||||
$quiz->questions = quiz_move_question_down($quiz->questions, $down);
|
||||
quiz_save_new_layout($quiz);
|
||||
redirect($thispageurl);
|
||||
$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
|
||||
quiz_delete_previews($quiz);
|
||||
redirect($afteractionurl);
|
||||
}
|
||||
|
||||
if (optional_param('repaginate', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
// Re-paginate the quiz
|
||||
$questionsperpage = optional_param('questionsperpage', $quiz->questionsperpage, PARAM_INT);
|
||||
$quiz->questions = quiz_repaginate($quiz->questions, $questionsperpage );
|
||||
quiz_save_new_layout($quiz);
|
||||
$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
|
||||
quiz_delete_previews($quiz);
|
||||
redirect($afteractionurl);
|
||||
}
|
||||
|
||||
if (($addquestion = optional_param('addquestion', 0, PARAM_INT)) && confirm_sesskey()) {
|
||||
/// Add a single question to the current quiz
|
||||
// Add a single question to the current quiz
|
||||
$addonpage = optional_param('addonpage', 0, PARAM_INT);
|
||||
quiz_add_quiz_question($addquestion, $quiz, $addonpage);
|
||||
quiz_update_sumgrades($quiz);
|
||||
quiz_delete_previews($quiz);
|
||||
quiz_update_sumgrades($quiz);
|
||||
$thispageurl->param('lastchanged', $addquestion);
|
||||
redirect($thispageurl);
|
||||
redirect($afteractionurl);
|
||||
}
|
||||
|
||||
if (optional_param('add', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
/// Add selected questions to the current quiz
|
||||
// Add selected questions to the current quiz
|
||||
$rawdata = (array) data_submitted();
|
||||
foreach ($rawdata as $key => $value) { // Parse input for question ids
|
||||
if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
|
||||
@ -222,15 +229,11 @@ if (optional_param('add', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
quiz_add_quiz_question($key, $quiz);
|
||||
}
|
||||
}
|
||||
quiz_update_sumgrades($quiz);
|
||||
quiz_delete_previews($quiz);
|
||||
redirect($thispageurl);
|
||||
quiz_update_sumgrades($quiz);
|
||||
redirect($afteractionurl);
|
||||
}
|
||||
|
||||
$qcobject = new question_category_object($pagevars['cpage'], $thispageurl,
|
||||
$contexts->having_one_edit_tab_cap('categories'), $defaultcategoryobj->id,
|
||||
$defaultcategory, null, $contexts->having_cap('moodle/question:add'));
|
||||
|
||||
if ((optional_param('addrandom', false, PARAM_BOOL)) && confirm_sesskey()) {
|
||||
// Add random questions to the quiz
|
||||
$recurse = optional_param('recurse', 0, PARAM_BOOL);
|
||||
@ -239,31 +242,35 @@ if ((optional_param('addrandom', false, PARAM_BOOL)) && confirm_sesskey()) {
|
||||
$randomcount = required_param('randomcount', PARAM_INT);
|
||||
quiz_add_random_questions($quiz, $addonpage, $categoryid, $randomcount, $recurse);
|
||||
|
||||
quiz_update_sumgrades($quiz);
|
||||
quiz_delete_previews($quiz);
|
||||
redirect($thispageurl);
|
||||
quiz_update_sumgrades($quiz);
|
||||
redirect($afteractionurl);
|
||||
}
|
||||
|
||||
if (optional_param('addnewpagesafterselected', null, PARAM_CLEAN) && !empty($selectedquestionids) && confirm_sesskey()) {
|
||||
if (optional_param('addnewpagesafterselected', null, PARAM_CLEAN) &&
|
||||
!empty($selectedquestionids) && confirm_sesskey()) {
|
||||
foreach ($selectedquestionids as $questionid) {
|
||||
$quiz->questions = quiz_add_page_break_after($quiz->questions, $questionid);
|
||||
}
|
||||
quiz_save_new_layout($quiz);
|
||||
redirect($thispageurl);
|
||||
$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
|
||||
quiz_delete_previews($quiz);
|
||||
redirect($afteractionurl);
|
||||
}
|
||||
|
||||
$addpage = optional_param('addpage', false, PARAM_INT);
|
||||
if ($addpage !== false && confirm_sesskey()) {
|
||||
$quiz->questions = quiz_add_page_break_at($quiz->questions, $addpage);
|
||||
quiz_save_new_layout($quiz);
|
||||
redirect($thispageurl);
|
||||
$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
|
||||
quiz_delete_previews($quiz);
|
||||
redirect($afteractionurl);
|
||||
}
|
||||
|
||||
$deleteemptypage = optional_param('deleteemptypage', false, PARAM_INT);
|
||||
if (($deleteemptypage !== false) && confirm_sesskey()) {
|
||||
$quiz->questions = quiz_delete_empty_page($quiz->questions, $deleteemptypage);
|
||||
quiz_save_new_layout($quiz);
|
||||
redirect($thispageurl);
|
||||
$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
|
||||
quiz_delete_previews($quiz);
|
||||
redirect($afteractionurl);
|
||||
}
|
||||
|
||||
$remove = optional_param('remove', false, PARAM_INT);
|
||||
@ -271,19 +278,23 @@ if (($remove = optional_param('remove', false, PARAM_INT)) && confirm_sesskey())
|
||||
quiz_remove_question($quiz, $remove);
|
||||
quiz_update_sumgrades($quiz);
|
||||
quiz_delete_previews($quiz);
|
||||
redirect($thispageurl);
|
||||
redirect($afteractionurl);
|
||||
}
|
||||
|
||||
if (optional_param('quizdeleteselected', false, PARAM_BOOL) && !empty($selectedquestionids) && confirm_sesskey()) {
|
||||
if (optional_param('quizdeleteselected', false, PARAM_BOOL) &&
|
||||
!empty($selectedquestionids) && confirm_sesskey()) {
|
||||
foreach ($selectedquestionids as $questionid) {
|
||||
quiz_remove_question($quiz, $questionid);
|
||||
}
|
||||
quiz_update_sumgrades($quiz);
|
||||
quiz_delete_previews($quiz);
|
||||
redirect($thispageurl);
|
||||
quiz_update_sumgrades($quiz);
|
||||
redirect($afteractionurl);
|
||||
}
|
||||
|
||||
if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
$deletepreviews = false;
|
||||
$recomputesummarks = false;
|
||||
|
||||
$oldquestions = explode(',', $quiz->questions); // the questions in the old order
|
||||
$questions = array(); // for questions in the new order
|
||||
$rawdata = (array) data_submitted();
|
||||
@ -295,15 +306,15 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
|
||||
foreach ($rawdata as $key => $value) {
|
||||
if (preg_match('!^g([0-9]+)$!', $key, $matches)) {
|
||||
/// Parse input for question -> grades
|
||||
// Parse input for question -> grades
|
||||
$questionid = $matches[1];
|
||||
$quiz->grades[$questionid] = clean_param($value, PARAM_FLOAT);
|
||||
quiz_update_question_instance($quiz->grades[$questionid], $questionid, $quiz->id);
|
||||
quiz_delete_previews($quiz);
|
||||
quiz_update_sumgrades($quiz);
|
||||
quiz_update_question_instance($quiz->grades[$questionid], $questionid, $quiz);
|
||||
$deletepreviews = true;
|
||||
$recomputesummarks = true;
|
||||
|
||||
} else if (preg_match('!^o(pg)?([0-9]+)$!', $key, $matches)) {
|
||||
/// Parse input for ordering info
|
||||
// Parse input for ordering info
|
||||
$questionid = $matches[2];
|
||||
// Make sure two questions don't overwrite each other. If we get a second
|
||||
// question with the same position, shift the second one along to the next gap.
|
||||
@ -317,6 +328,7 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
} else {
|
||||
$questions[$value] = $questionid;
|
||||
}
|
||||
$deletepreviews = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,8 +337,8 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
ksort($questions);
|
||||
$questions[] = 0;
|
||||
$quiz->questions = implode(',', $questions);
|
||||
quiz_save_new_layout($quiz);
|
||||
quiz_delete_previews($quiz);
|
||||
$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
|
||||
$deletepreviews = true;
|
||||
}
|
||||
|
||||
//get a list of questions to move, later to be added in the appropriate
|
||||
@ -350,8 +362,8 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
$moveselectedpos = $pagebreakpositions[$moveselectedonpage - 1];
|
||||
array_splice($questions, $moveselectedpos, 0, $selectedquestionids);
|
||||
$quiz->questions = implode(',', $questions);
|
||||
quiz_save_new_layout($quiz);
|
||||
quiz_delete_previews($quiz);
|
||||
$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
|
||||
$deletepreviews = true;
|
||||
}
|
||||
|
||||
// If rescaling is required save the new maximum
|
||||
@ -360,7 +372,16 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
quiz_set_grade($maxgrade, $quiz);
|
||||
}
|
||||
|
||||
redirect($thispageurl);
|
||||
if ($deletepreviews) {
|
||||
quiz_delete_previews($quiz);
|
||||
}
|
||||
if ($recomputesummarks) {
|
||||
quiz_update_sumgrades($quiz);
|
||||
quiz_update_all_attempt_sumgrades($quiz);
|
||||
quiz_update_all_final_grades($quiz);
|
||||
quiz_update_grades($quiz, 0, true);
|
||||
}
|
||||
redirect($afteractionurl);
|
||||
}
|
||||
|
||||
$questionbank->process_actions($thispageurl, $cm);
|
||||
@ -369,8 +390,10 @@ $questionbank->process_actions($thispageurl, $cm);
|
||||
|
||||
$PAGE->requires->yui2_lib('container');
|
||||
$PAGE->requires->yui2_lib('dragdrop');
|
||||
$PAGE->requires->skip_link_to('questionbank', get_string('skipto', 'access', get_string('questionbank', 'question')));
|
||||
$PAGE->requires->skip_link_to('quizcontentsblock', get_string('skipto', 'access', get_string('questionsinthisquiz', 'quiz')));
|
||||
$PAGE->requires->skip_link_to('questionbank',
|
||||
get_string('skipto', 'access', get_string('questionbank', 'question')));
|
||||
$PAGE->requires->skip_link_to('quizcontentsblock',
|
||||
get_string('skipto', 'access', get_string('questionsinthisquiz', 'quiz')));
|
||||
$PAGE->set_title($pagetitle);
|
||||
$PAGE->set_heading($course->fullname);
|
||||
$node = $PAGE->settingsnav->find('mod_quiz_edit', navigation_node::TYPE_SETTING);
|
||||
@ -380,7 +403,7 @@ if ($node) {
|
||||
echo $OUTPUT->header();
|
||||
|
||||
// Initialise the JavaScript.
|
||||
$quizeditconfig = new stdClass;
|
||||
$quizeditconfig = new stdClass();
|
||||
$quizeditconfig->url = $thispageurl->out(true, array('qbanktool' => '0'));
|
||||
$quizeditconfig->dialoglisteners = array();
|
||||
$numberoflisteners = max(quiz_number_of_pages($quiz->questions), 1);
|
||||
@ -388,7 +411,9 @@ for ($pageiter = 1; $pageiter <= $numberoflisteners; $pageiter++) {
|
||||
$quizeditconfig->dialoglisteners[] = 'addrandomdialoglaunch_' . $pageiter;
|
||||
}
|
||||
$PAGE->requires->data_for_js('quiz_edit_config', $quizeditconfig);
|
||||
$PAGE->requires->js('/question/qengine.js');
|
||||
$PAGE->requires->js('/mod/quiz/edit.js');
|
||||
$PAGE->requires->js_init_call('quiz_edit_init');
|
||||
|
||||
// Print the tabs to switch mode.
|
||||
if ($quiz_reordertool) {
|
||||
@ -397,8 +422,10 @@ if ($quiz_reordertool) {
|
||||
$currenttab = 'edit';
|
||||
}
|
||||
$tabs = array(array(
|
||||
new tabobject('edit', new moodle_url($thispageurl, array('reordertool' => 0)), get_string('editingquiz', 'quiz')),
|
||||
new tabobject('reorder', new moodle_url($thispageurl, array('reordertool' => 1)), get_string('orderingquiz', 'quiz')),
|
||||
new tabobject('edit', new moodle_url($thispageurl,
|
||||
array('reordertool' => 0)), get_string('editingquiz', 'quiz')),
|
||||
new tabobject('reorder', new moodle_url($thispageurl,
|
||||
array('reordertool' => 1)), get_string('orderingquiz', 'quiz')),
|
||||
));
|
||||
print_tabs($tabs, $currenttab);
|
||||
|
||||
@ -447,7 +474,8 @@ if ($quiz->shufflequestions) {
|
||||
$repaginatingdisabled = false;
|
||||
}
|
||||
if ($quiz_reordertool) {
|
||||
echo '<div class="repaginatecommand"><button id="repaginatecommand" '.$repaginatingdisabledhtml.'>'.
|
||||
echo '<div class="repaginatecommand"><button id="repaginatecommand" ' .
|
||||
$repaginatingdisabledhtml.'>'.
|
||||
get_string('repaginatecommand', 'quiz').'...</button>';
|
||||
echo '</div>';
|
||||
}
|
||||
@ -501,10 +529,12 @@ if ($quiz_reordertool) {
|
||||
echo '<input type="hidden" name="repaginate" value="'.$gostring.'" />';
|
||||
$attributes = array();
|
||||
$attributes['disabled'] = $repaginatingdisabledhtml ? 'disabled' : null;
|
||||
$select = html_writer::select($perpage, 'questionsperpage', $quiz->questionsperpage, null, $attributes);
|
||||
$select = html_writer::select(
|
||||
$perpage, 'questionsperpage', $quiz->questionsperpage, null, $attributes);
|
||||
print_string('repaginate', 'quiz', $select);
|
||||
echo '<div class="quizquestionlistcontrols">';
|
||||
echo ' <input type="submit" name="repaginate" value="'. $gostring .'" '.$repaginatingdisabledhtml.' />';
|
||||
echo ' <input type="submit" name="repaginate" value="'. $gostring . '" ' .
|
||||
$repaginatingdisabledhtml.' />';
|
||||
echo '</div></fieldset></form></div></div>';
|
||||
}
|
||||
|
||||
@ -529,16 +559,15 @@ if (!$quiz_reordertool) {
|
||||
'cmid' => $cm->id,
|
||||
));
|
||||
?>
|
||||
<div id="randomquestiondialog">
|
||||
<div class="hd"><?php print_string('addrandomquestiontoquiz', 'quiz', $quiz->name); ?>
|
||||
<span id="pagenumber"><!-- JavaScript will insert the page number here. -->
|
||||
</span>
|
||||
</div>
|
||||
<div class="bd"><?php
|
||||
$randomform->display();
|
||||
?></div>
|
||||
</div>
|
||||
<div id="randomquestiondialog">
|
||||
<div class="hd"><?php print_string('addrandomquestiontoquiz', 'quiz', $quiz->name); ?>
|
||||
<span id="pagenumber"><!-- JavaScript will insert the page number here. -->
|
||||
</span>
|
||||
</div>
|
||||
<div class="bd"><?php
|
||||
$randomform->display();
|
||||
?></div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
echo $OUTPUT->footer();
|
||||
?>
|
||||
|
@ -1,34 +1,35 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// NOTICE OF COPYRIGHT //
|
||||
// //
|
||||
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
|
||||
// http://moodle.org //
|
||||
// //
|
||||
// Copyright (C) 1999 onwards Martin Dougiamas and others //
|
||||
// //
|
||||
// This program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2 of the License, or //
|
||||
// (at your option) any later version. //
|
||||
// //
|
||||
// This program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details: //
|
||||
// //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Functions used by edit.php to edit quizzes
|
||||
* This contains functions that are called from within the quiz module only
|
||||
* Functions that are also called by core Moodle are in {@link lib.php}
|
||||
* This script also loads the code in {@link questionlib.php} which holds
|
||||
* the module-indpendent code for handling questions and which in turn
|
||||
* initialises all the questiontype classes.
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @package quiz
|
||||
*//** */
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
* @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
||||
@ -51,13 +52,14 @@ function quiz_remove_question($quiz, $questionid) {
|
||||
unset($questionids[$key]);
|
||||
$quiz->questions = implode(',', $questionids);
|
||||
$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
|
||||
$DB->delete_records('quiz_question_instances', array('quiz' => $quiz->instance, 'question' => $questionid));
|
||||
$DB->delete_records('quiz_question_instances',
|
||||
array('quiz' => $quiz->instance, 'question' => $questionid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an empty page from the quiz layout. If that is not possible, do nothing.
|
||||
* @param string $layout the existinng layout, $quiz->questions.
|
||||
* @param integer $index the position into $layout where the empty page should be removed.
|
||||
* @param int $index the position into $layout where the empty page should be removed.
|
||||
* @return the updated layout
|
||||
*/
|
||||
function quiz_delete_empty_page($layout, $index) {
|
||||
@ -85,8 +87,9 @@ function quiz_delete_empty_page($layout, $index) {
|
||||
* @param int $id The id of the question to be added
|
||||
* @param object $quiz The extended quiz object as used by edit.php
|
||||
* This is updated by this function
|
||||
* @param int $page Which page in quiz to add the question on. If 0 (default), add at the end
|
||||
* @return boolean false if the question was already in the quiz
|
||||
* @param int $page Which page in quiz to add the question on. If 0 (default),
|
||||
* add at the end
|
||||
* @return bool false if the question was already in the quiz
|
||||
*/
|
||||
function quiz_add_quiz_question($id, $quiz, $page = 0) {
|
||||
global $DB;
|
||||
@ -141,15 +144,17 @@ function quiz_add_quiz_question($id, $quiz, $page = 0) {
|
||||
$quiz->questions = implode(',', $questions);
|
||||
$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
|
||||
|
||||
// update question grades
|
||||
$quiz->grades[$id] = $DB->get_field('question', 'defaultgrade', array('id' => $id));
|
||||
quiz_update_question_instance($quiz->grades[$id], $id, $quiz->instance);
|
||||
|
||||
return true;
|
||||
// Add the new question instance.
|
||||
$instance = new stdClass();
|
||||
$instance->quiz = $quiz->id;
|
||||
$instance->question = $id;
|
||||
$instance->grade = $DB->get_field('question', 'defaultmark', array('id' => $id));
|
||||
$DB->insert_record('quiz_question_instances', $instance);
|
||||
}
|
||||
|
||||
function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number, $includesubcategories) {
|
||||
global $DB, $QTYPES;
|
||||
function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number,
|
||||
$includesubcategories) {
|
||||
global $DB;
|
||||
|
||||
$category = $DB->get_record('question_categories', array('id' => $categoryid));
|
||||
if (!$category) {
|
||||
@ -162,11 +167,14 @@ function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number, $inc
|
||||
// Find existing random questions in this category that are
|
||||
// not used by any quiz.
|
||||
if ($existingquestions = $DB->get_records_sql(
|
||||
"SELECT q.id,q.qtype FROM {question} q
|
||||
WHERE qtype = '" . RANDOM . "'
|
||||
"SELECT q.id, q.qtype FROM {question} q
|
||||
WHERE qtype = 'random'
|
||||
AND category = ?
|
||||
AND " . $DB->sql_compare_text('questiontext') . " = ?
|
||||
AND NOT EXISTS (SELECT * FROM {quiz_question_instances} WHERE question = q.id)
|
||||
AND NOT EXISTS (
|
||||
SELECT *
|
||||
FROM {quiz_question_instances}
|
||||
WHERE question = q.id)
|
||||
ORDER BY id", array($category->id, $includesubcategories))) {
|
||||
// Take as many of these as needed.
|
||||
while (($existingquestion = array_shift($existingquestions)) && $number > 0) {
|
||||
@ -180,15 +188,16 @@ function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number, $inc
|
||||
}
|
||||
|
||||
// More random questions are needed, create them.
|
||||
$form->questiontext = array('text' => $includesubcategories, 'format' => 0);
|
||||
$form->defaultgrade = 1;
|
||||
$form->hidden = 1;
|
||||
for ($i = 0; $i < $number; $i += 1) {
|
||||
$form = new stdClass();
|
||||
$form->questiontext = array('text' => $includesubcategories, 'format' => 0);
|
||||
$form->category = $category->id . ',' . $category->contextid;
|
||||
$form->defaultmark = 1;
|
||||
$form->hidden = 1;
|
||||
$form->stamp = make_unique_id_code(); // Set the unique code (not to be changed)
|
||||
$question = new stdClass;
|
||||
$question->qtype = RANDOM;
|
||||
$question = $QTYPES[RANDOM]->save_question($question, $form);
|
||||
$question = new stdClass();
|
||||
$question->qtype = 'random';
|
||||
$question = question_bank::get_qtype('random')->save_question($question, $form);
|
||||
if (!isset($question->id)) {
|
||||
print_error('cannotinsertrandomquestion', 'quiz');
|
||||
}
|
||||
@ -199,7 +208,7 @@ function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number, $inc
|
||||
/**
|
||||
* Add a page break after at particular position$.
|
||||
* @param string $layout the existinng layout, $quiz->questions.
|
||||
* @param integer $index the position into $layout where the empty page should be removed.
|
||||
* @param int $index the position into $layout where the empty page should be removed.
|
||||
* @return the updated layout
|
||||
*/
|
||||
function quiz_add_page_break_at($layout, $index) {
|
||||
@ -216,7 +225,7 @@ function quiz_add_page_break_at($layout, $index) {
|
||||
/**
|
||||
* Add a page break after a particular question.
|
||||
* @param string $layout the existinng layout, $quiz->questions.
|
||||
* @param integer $qustionid the question to add the page break after.
|
||||
* @param int $qustionid the question to add the page break after.
|
||||
* @return the updated layout
|
||||
*/
|
||||
function quiz_add_page_break_after($layout, $questionid) {
|
||||
@ -248,23 +257,30 @@ function quiz_save_new_layout($quiz) {
|
||||
*
|
||||
* Saves changes to the question grades in the quiz_question_instances table.
|
||||
* It does not update 'sumgrades' in the quiz table.
|
||||
* @return boolean Indicates success or failure.
|
||||
* @param integer grade The maximal grade for the question
|
||||
* @param integer $questionid The id of the question
|
||||
* @param integer $quizid The id of the quiz to update / add the instances for.
|
||||
*
|
||||
* @param int grade The maximal grade for the question
|
||||
* @param int $questionid The id of the question
|
||||
* @param int $quizid The id of the quiz to update / add the instances for.
|
||||
*/
|
||||
function quiz_update_question_instance($grade, $questionid, $quizid) {
|
||||
function quiz_update_question_instance($grade, $questionid, $quiz) {
|
||||
global $DB;
|
||||
if ($instance = $DB->get_record('quiz_question_instances', array('quiz' => $quizid, 'question' => $questionid))) {
|
||||
$instance->grade = $grade;
|
||||
return $DB->update_record('quiz_question_instances', $instance);
|
||||
} else {
|
||||
unset($instance);
|
||||
$instance->quiz = $quizid;
|
||||
$instance->question = $questionid;
|
||||
$instance->grade = $grade;
|
||||
return $DB->insert_record('quiz_question_instances', $instance);
|
||||
$instance = $DB->get_record('quiz_question_instances', array('quiz' => $quiz->id,
|
||||
'question' => $questionid));
|
||||
$slot = quiz_get_slot_for_question($quiz, $questionid);
|
||||
|
||||
if (!$instance || !$slot) {
|
||||
throw new coding_exception('Attempt to change the grade of a quesion not in the quiz.');
|
||||
}
|
||||
|
||||
if (abs($grade - $instance->grade) < 1e-7) {
|
||||
// Grade has not changed. Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
$instance->grade = $grade;
|
||||
$DB->update_record('quiz_question_instances', $instance);
|
||||
question_engine::set_max_mark_in_attempts(new qubaids_for_quiz($quiz->id),
|
||||
$slot, $grade);
|
||||
}
|
||||
|
||||
// Private function used by the following two.
|
||||
@ -295,7 +311,7 @@ function _quiz_move_question($layout, $questionid, $shift) {
|
||||
* Move a particular question one space earlier in the $quiz->questions list.
|
||||
* If that is not possible, do nothing.
|
||||
* @param string $layout the existinng layout, $quiz->questions.
|
||||
* @param integer $questionid the id of a question.
|
||||
* @param int $questionid the id of a question.
|
||||
* @return the updated layout
|
||||
*/
|
||||
function quiz_move_question_up($layout, $questionid) {
|
||||
@ -306,7 +322,7 @@ function quiz_move_question_up($layout, $questionid) {
|
||||
* Move a particular question one space later in the $quiz->questions list.
|
||||
* If that is not possible, do nothing.
|
||||
* @param string $layout the existinng layout, $quiz->questions.
|
||||
* @param integer $questionid the id of a question.
|
||||
* @param int $questionid the id of a question.
|
||||
* @return the updated layout
|
||||
*/
|
||||
function quiz_move_question_down($layout, $questionid) {
|
||||
@ -323,14 +339,14 @@ function quiz_move_question_down($layout, $questionid) {
|
||||
* $quiz->grades
|
||||
* @param object $pageurl The url of the current page with the parameters required
|
||||
* for links returning to the current page, as a moodle_url object
|
||||
* @param boolean $allowdelete Indicates whether the delete icons should be displayed
|
||||
* @param boolean $reordertool Indicates whether the reorder tool should be displayed
|
||||
* @param boolean $quiz_qbanktool Indicates whether the question bank should be displayed
|
||||
* @param boolean $hasattempts Indicates whether the quiz has attempts
|
||||
* @param bool $allowdelete Indicates whether the delete icons should be displayed
|
||||
* @param bool $reordertool Indicates whether the reorder tool should be displayed
|
||||
* @param bool $quiz_qbanktool Indicates whether the question bank should be displayed
|
||||
* @param bool $hasattempts Indicates whether the quiz has attempts
|
||||
*/
|
||||
function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
|
||||
$quiz_qbanktool, $hasattempts, $defaultcategoryobj) {
|
||||
global $USER, $CFG, $QTYPES, $DB, $OUTPUT;
|
||||
global $USER, $CFG, $DB, $OUTPUT;
|
||||
$strorder = get_string('order');
|
||||
$strquestionname = get_string('questionname', 'quiz');
|
||||
$strgrade = get_string('grade');
|
||||
@ -351,11 +367,12 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
|
||||
|
||||
if ($quiz->questions) {
|
||||
list($usql, $params) = $DB->get_in_or_equal(explode(',', $quiz->questions));
|
||||
$questions = $DB->get_records_sql("SELECT q.*,c.contextid
|
||||
FROM {question} q,
|
||||
{question_categories} c
|
||||
WHERE q.id $usql
|
||||
AND q.category = c.id", $params);
|
||||
$params[] = $quiz->id;
|
||||
$questions = $DB->get_records_sql("SELECT q.*, qc.contextid, qqi.grade as maxmark
|
||||
FROM {question} q
|
||||
JOIN {question_categories} qc ON qc.id = q.category
|
||||
JOIN {quiz_question_instances} qqi ON qqi.question = q.id
|
||||
WHERE q.id $usql AND qqi.quiz = ?", $params);
|
||||
} else {
|
||||
$questions = array();
|
||||
}
|
||||
@ -429,20 +446,15 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
|
||||
$qno = 1;
|
||||
//the current question (includes questions and descriptions)
|
||||
$questioncount = 0;
|
||||
//the ordinal of current element in the layout
|
||||
//(includes page breaks, questions and descriptions)
|
||||
$count = 0;
|
||||
//the current page number in iteration
|
||||
$pagecount = 0;
|
||||
|
||||
$sumgrade = 0;
|
||||
|
||||
$pageopen = false;
|
||||
|
||||
$returnurl = str_replace($CFG->wwwroot, '', $pageurl->out(false));
|
||||
$questiontotalcount = count($order);
|
||||
|
||||
foreach ($order as $i => $qnum) {
|
||||
foreach ($order as $count => $qnum) {
|
||||
|
||||
$reordercheckbox = '';
|
||||
$reordercheckboxlabel = '';
|
||||
@ -451,10 +463,23 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
|
||||
if ($qnum && empty($questions[$qnum])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the questiontype is missing change the question type
|
||||
if ($qnum && !array_key_exists($questions[$qnum]->qtype, $QTYPES)) {
|
||||
if ($qnum && !array_key_exists($qnum, $questions)) {
|
||||
$fakequestion = new stdClass();
|
||||
$fakequestion->id = 0;
|
||||
$fakequestion->qtype = 'missingtype';
|
||||
$fakequestion->name = get_string('deletedquestion', 'qtype_missingtype');
|
||||
$fakequestion->questiontext = '<p>' .
|
||||
get_string('deletedquestion', 'qtype_missing') . '</p>';
|
||||
$fakequestion->length = 0;
|
||||
$questions[$qnum] = $fakequestion;
|
||||
$quiz->grades[$qnum] = 0;
|
||||
|
||||
} else if ($qnum && !question_bank::qtype_exists($questions[$qnum]->qtype)) {
|
||||
$questions[$qnum]->qtype = 'missingtype';
|
||||
}
|
||||
|
||||
if ($qnum != 0 || ($qnum == 0 && !$pageopen)) {
|
||||
//this is either a question or a page break after another
|
||||
// (no page is currently open)
|
||||
@ -466,17 +491,19 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
|
||||
'</span><div class="pagecontent">';
|
||||
$pageopen = true;
|
||||
}
|
||||
if ($qnum == 0 && $i < $questiontotalcount) {
|
||||
if ($qnum == 0 && $count < $questiontotalcount) {
|
||||
// This is the second successive page break. Tell the user the page is empty.
|
||||
echo '<div class="pagestatus">';
|
||||
print_string('noquestionsonpage', 'quiz');
|
||||
echo '</div>';
|
||||
if ($allowdelete) {
|
||||
echo '<div class="quizpagedelete">';
|
||||
echo '<a title="' . get_string('removeemptypage', 'quiz') . '" href="' .
|
||||
$pageurl->out(true, array('deleteemptypage' => $i - 1, 'sesskey'=>sesskey())) .
|
||||
'"><img src="' . $OUTPUT->pix_url('t/delete') . '" ' .
|
||||
'class="iconsmall" alt="' . $strremove . '" /></a>';
|
||||
echo $OUTPUT->action_icon($pageurl->out(true,
|
||||
array('deleteemptypage' => $count - 1, 'sesskey'=>sesskey())),
|
||||
new pix_icon('t/delete', $strremove),
|
||||
new component_action('click',
|
||||
'M.core_scroll_manager.save_scroll_action'),
|
||||
array('title' => $strremove));
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
@ -493,7 +520,7 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
|
||||
//this is an actual question
|
||||
|
||||
/* Display question start */
|
||||
?>
|
||||
?>
|
||||
<div class="question">
|
||||
<div class="questioncontainer <?php echo $question->qtype; ?>">
|
||||
<div class="qnum">
|
||||
@ -536,28 +563,35 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
|
||||
if ($count >= $lastindex - 1) {
|
||||
$upbuttonclass = 'upwithoutdown';
|
||||
}
|
||||
echo "<a title=\"$strmoveup\" href=\"" .
|
||||
$pageurl->out(true, array('up' => $question->id, 'sesskey'=>sesskey())) . "\"><img
|
||||
src=\"" . $OUTPUT->pix_url('t/up') . "\" class=\"iconsmall
|
||||
$upbuttonclass\" alt=\"$strmoveup\" /></a>";
|
||||
echo $OUTPUT->action_icon($pageurl->out(true,
|
||||
array('up' => $question->id, 'sesskey'=>sesskey())),
|
||||
new pix_icon('t/up', $strmoveup),
|
||||
new component_action('click',
|
||||
'M.core_scroll_manager.save_scroll_action'),
|
||||
array('title' => $strmoveup));
|
||||
}
|
||||
|
||||
}
|
||||
if ($count < $lastindex - 1) {
|
||||
if (!$hasattempts) {
|
||||
echo "<a title=\"$strmovedown\" href=\"" .
|
||||
$pageurl->out(true, array('down' => $question->id, 'sesskey'=>sesskey())) . "\"><img
|
||||
src=\"" . $OUTPUT->pix_url('t/down') . "\" class=\"iconsmall\"" .
|
||||
" alt=\"$strmovedown\" /></a>";
|
||||
echo $OUTPUT->action_icon($pageurl->out(true,
|
||||
array('down' => $question->id, 'sesskey'=>sesskey())),
|
||||
new pix_icon('t/down', $strmovedown),
|
||||
new component_action('click',
|
||||
'M.core_scroll_manager.save_scroll_action'),
|
||||
array('title' => $strmovedown));
|
||||
}
|
||||
}
|
||||
if ($allowdelete && question_has_capability_on($question, 'use', $question->category)) {
|
||||
if ($allowdelete && (empty($question->id) ||
|
||||
question_has_capability_on($question, 'use', $question->category))) {
|
||||
// remove from quiz, not question delete.
|
||||
if (!$hasattempts) {
|
||||
echo "<a title=\"$strremove\" href=\"" .
|
||||
$pageurl->out(true, array('remove' => $question->id, 'sesskey'=>sesskey())) . "\">
|
||||
<img src=\"" . $OUTPUT->pix_url('t/delete') . "\" " .
|
||||
"class=\"iconsmall\" alt=\"$strremove\" /></a>";
|
||||
echo $OUTPUT->action_icon($pageurl->out(true,
|
||||
array('remove' => $question->id, 'sesskey'=>sesskey())),
|
||||
new pix_icon('t/delete', $strremove),
|
||||
new component_action('click',
|
||||
'M.core_scroll_manager.save_scroll_action'),
|
||||
array('title' => $strremove));
|
||||
}
|
||||
}
|
||||
?>
|
||||
@ -565,46 +599,50 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
|
||||
if ($question->qtype != 'description' && !$reordertool) {
|
||||
?>
|
||||
<div class="points">
|
||||
<form method="post" action="edit.php"><div>
|
||||
<form method="post" action="edit.php" class="quizsavegradesform"><div>
|
||||
<fieldset class="invisiblefieldset" style="display: block;">
|
||||
<label for="<?php echo "inputq$question->id" ?>"><?php echo $strgrade; ?></label>:<br />
|
||||
<input type="hidden" name="sesskey" value="<?php echo sesskey() ?>" />
|
||||
<?php echo html_writer::input_hidden_params($pageurl); ?>
|
||||
<input type="hidden" name="savechanges" value="save" />
|
||||
<?php
|
||||
echo '<input type="text" name="g' . $question->id . '" id="inputq' . $question->id .
|
||||
'" size="' . ($quiz->decimalpoints + 2) . '" value="' . (0 + $quiz->grades[$qnum]) .
|
||||
echo '<input type="text" name="g' . $question->id .
|
||||
'" id="inputq' . $question->id .
|
||||
'" size="' . ($quiz->decimalpoints + 2) .
|
||||
'" value="' . (0 + $quiz->grades[$qnum]) .
|
||||
'" tabindex="' . ($lastindex + $qno) . '" />';
|
||||
?>
|
||||
<input type="submit" class="pointssubmitbutton" value="<?php echo $strsave; ?>" />
|
||||
</fieldset>
|
||||
<?php if ($question->qtype == 'random') {
|
||||
echo '<a href="' . $questionurl->out() . '" class="configurerandomquestion">' . get_string("configurerandomquestion", "quiz") . '</a>';
|
||||
}
|
||||
<?php
|
||||
if ($question->qtype == 'random') {
|
||||
echo '<a href="' . $questionurl->out() .
|
||||
'" class="configurerandomquestion">' .
|
||||
get_string("configurerandomquestion", "quiz") . '</a>';
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
<?php
|
||||
} else if ($reordertool) {
|
||||
if ($qnum) {
|
||||
?>
|
||||
<div class="qorder">
|
||||
<?php
|
||||
echo '<input type="text" name="o' . $question->id . '" size="2" value="' .
|
||||
(10*$count + 10) .
|
||||
'" tabindex="' . ($lastindex + $qno) .
|
||||
'" />';
|
||||
echo '<input type="text" name="o' . $question->id .
|
||||
'" size="2" value="' . (10*$count + 10) .
|
||||
'" tabindex="' . ($lastindex + $qno) . '" />';
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
||||
<div class="questioncontentcontainer">
|
||||
<?php
|
||||
<?php
|
||||
if ($question->qtype == 'random') { // it is a random question
|
||||
if (!$reordertool) {
|
||||
quiz_print_randomquestion($question, $pageurl, $quiz, $quiz_qbanktool);
|
||||
@ -625,19 +663,16 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
|
||||
</div>
|
||||
|
||||
<?php
|
||||
/* Display question end */
|
||||
$count++;
|
||||
$sumgrade += $quiz->grades[$qnum];
|
||||
|
||||
}
|
||||
}
|
||||
//a page break: end the existing page.
|
||||
if ($qnum == 0) {
|
||||
if ($pageopen) {
|
||||
if (!$reordertool && !($quiz->shufflequestions && $i < $questiontotalcount - 1)) {
|
||||
if (!$reordertool && !($quiz->shufflequestions &&
|
||||
$count < $questiontotalcount - 1)) {
|
||||
quiz_print_pagecontrols($quiz, $pageurl, $pagecount,
|
||||
$hasattempts, $defaultcategoryobj);
|
||||
} else if ($i < $questiontotalcount - 1) {
|
||||
} else if ($count < $questiontotalcount - 1) {
|
||||
//do not include the last page break for reordering
|
||||
//to avoid creating a new extra page in the end
|
||||
echo '<input type="hidden" name="opg' . $pagecount . '" size="2" value="' .
|
||||
@ -647,8 +682,13 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
|
||||
|
||||
if (!$reordertool && !$quiz->shufflequestions) {
|
||||
echo $OUTPUT->container_start('addpage');
|
||||
$url = new moodle_url($pageurl->out_omit_querystring(), array('cmid' => $quiz->cmid, 'courseid' => $quiz->course, 'addpage' => $count, 'sesskey' => sesskey()));
|
||||
echo $OUTPUT->single_button($url, get_string('addpagehere', 'quiz'), 'get', array('disabled'=>$hasattempts));
|
||||
$url = new moodle_url($pageurl->out_omit_querystring(),
|
||||
array('cmid' => $quiz->cmid, 'courseid' => $quiz->course,
|
||||
'addpage' => $count, 'sesskey' => sesskey()));
|
||||
echo $OUTPUT->single_button($url, get_string('addpagehere', 'quiz'), 'post',
|
||||
array('disabled' => $hasattempts,
|
||||
'actions' => array(new component_action('click',
|
||||
'M.core_scroll_manager.save_scroll_action'))));
|
||||
echo $OUTPUT->container_end();
|
||||
}
|
||||
$pageopen = false;
|
||||
@ -661,8 +701,6 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
|
||||
echo $reordercontrolsbottom;
|
||||
echo '</div></form>';
|
||||
}
|
||||
|
||||
return $sumgrade;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -697,7 +735,8 @@ function quiz_print_pagecontrols($quiz, $pageurl, $page, $hasattempts, $defaultc
|
||||
$returnurladdtoquiz = str_replace($CFG->wwwroot, '', $returnurladdtoquiz->out(false));
|
||||
$newquestionparams = array('returnurl' => $returnurladdtoquiz,
|
||||
'cmid' => $quiz->cmid, 'appendqnumstring' => 'addquestion');
|
||||
create_new_question_button($defaultcategoryid, $newquestionparams, get_string('addaquestion', 'quiz'),
|
||||
create_new_question_button($defaultcategoryid, $newquestionparams,
|
||||
get_string('addaquestion', 'quiz'),
|
||||
get_string('createquestionandadd', 'quiz'), $hasattempts);
|
||||
|
||||
if ($hasattempts) {
|
||||
@ -707,14 +746,21 @@ function quiz_print_pagecontrols($quiz, $pageurl, $page, $hasattempts, $defaultc
|
||||
}
|
||||
?>
|
||||
<div class="singlebutton">
|
||||
<form class="randomquestionform" action="<?php echo $CFG->wwwroot; ?>/mod/quiz/addrandom.php" method="get">
|
||||
<form class="randomquestionform" action="<?php echo $CFG->wwwroot;
|
||||
?>/mod/quiz/addrandom.php" method="get">
|
||||
<div>
|
||||
<input type="hidden" class="addonpage_formelement" name="addonpage" value="<?php echo $page; ?>" />
|
||||
<input type="hidden" class="addonpage_formelement" name="addonpage" value="<?php
|
||||
echo $page; ?>" />
|
||||
<input type="hidden" name="cmid" value="<?php echo $quiz->cmid; ?>" />
|
||||
<input type="hidden" name="courseid" value="<?php echo $quiz->course; ?>" />
|
||||
<input type="hidden" name="category" value="<?php echo $pageurl->param('cat'); ?>" />
|
||||
<input type="hidden" name="returnurl" value="<?php echo s(str_replace($CFG->wwwroot, '', $pageurl->out(false))); ?>" />
|
||||
<input type="submit" id="addrandomdialoglaunch_<?php echo $randombuttoncount; ?>" value="<?php echo get_string('addarandomquestion', 'quiz'); ?>" <?php echo " $disabled"; ?> />
|
||||
<input type="hidden" name="category" value="<?php
|
||||
echo $pageurl->param('cat'); ?>" />
|
||||
<input type="hidden" name="returnurl" value="<?php
|
||||
echo s(str_replace($CFG->wwwroot, '', $pageurl->out(false))); ?>" />
|
||||
<input type="submit" id="addrandomdialoglaunch_<?php
|
||||
echo $randombuttoncount; ?>" value="<?php
|
||||
echo get_string('addarandomquestion', 'quiz'); ?>" <?php
|
||||
echo " $disabled"; ?> />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -732,14 +778,14 @@ function quiz_print_pagecontrols($quiz, $pageurl, $page, $hasattempts, $defaultc
|
||||
* @param object $quiz The quiz in the context of which the question is being displayed
|
||||
*/
|
||||
function quiz_print_singlequestion($question, $returnurl, $quiz) {
|
||||
global $QTYPES;
|
||||
echo '<div class="singlequestion">';
|
||||
echo quiz_question_edit_button($quiz->cmid, $question, $returnurl, quiz_question_tostring($question) . ' ');
|
||||
echo quiz_question_edit_button($quiz->cmid, $question, $returnurl,
|
||||
quiz_question_tostring($question) . ' ');
|
||||
echo '<span class="questiontype">';
|
||||
$namestr = $QTYPES[$question->qtype]->local_name();
|
||||
print_question_icon($question);
|
||||
echo " $namestr</span>";
|
||||
echo '<span class="questionpreview">' . quiz_question_preview_button($quiz, $question, true) . '</span>';
|
||||
echo ' ' . question_bank::get_qtype_name($question->qtype) . '</span>';
|
||||
echo '<span class="questionpreview">' .
|
||||
quiz_question_preview_button($quiz, $question, true) . '</span>';
|
||||
echo "</div>\n";
|
||||
}
|
||||
/**
|
||||
@ -749,13 +795,14 @@ function quiz_print_singlequestion($question, $returnurl, $quiz) {
|
||||
* @param object $question A question object from the database questions table
|
||||
* @param object $questionurl The url of the question editing page as a moodle_url object
|
||||
* @param object $quiz The quiz in the context of which the question is being displayed
|
||||
* @param boolean $quiz_qbanktool Indicate to this function if the question bank window open
|
||||
* @param bool $quiz_qbanktool Indicate to this function if the question bank window open
|
||||
*/
|
||||
function quiz_print_randomquestion(&$question, &$pageurl, &$quiz, $quiz_qbanktool) {
|
||||
global $DB, $QTYPES, $OUTPUT;
|
||||
global $DB, $OUTPUT;
|
||||
echo '<div class="quiz_randomquestion">';
|
||||
|
||||
if (!$category = $DB->get_record('question_categories', array('id' => $question->category))) {
|
||||
if (!$category = $DB->get_record('question_categories',
|
||||
array('id' => $question->category))) {
|
||||
echo $OUTPUT->notification('Random question category not found!');
|
||||
return;
|
||||
}
|
||||
@ -765,7 +812,7 @@ function quiz_print_randomquestion(&$question, &$pageurl, &$quiz, $quiz_qbanktoo
|
||||
print_random_option_icon($question);
|
||||
echo ' ' . get_string('randomfromcategory', 'quiz') . '</div>';
|
||||
|
||||
$a = new stdClass;
|
||||
$a = new stdClass();
|
||||
$a->arrow = $OUTPUT->rarrow();
|
||||
$strshowcategorycontents = get_string('showcategorycontents', 'quiz', $a);
|
||||
|
||||
@ -774,11 +821,13 @@ function quiz_print_randomquestion(&$question, &$pageurl, &$quiz, $quiz_qbanktoo
|
||||
$linkcategorycontents = ' <a href="' . $openqbankurl . '">' . $strshowcategorycontents . '</a>';
|
||||
|
||||
echo '<div class="randomquestioncategory">';
|
||||
echo '<a href="' . $openqbankurl . '" title="' . $strshowcategorycontents . '">' . $category->name . '</a>';
|
||||
echo '<span class="questionpreview">' . quiz_question_preview_button($quiz, $question, true) . '</span>';
|
||||
echo '<a href="' . $openqbankurl . '" title="' . $strshowcategorycontents . '">' .
|
||||
$category->name . '</a>';
|
||||
echo '<span class="questionpreview">' .
|
||||
quiz_question_preview_button($quiz, $question, true) . '</span>';
|
||||
echo '</div>';
|
||||
|
||||
$questionids = $QTYPES['random']->get_usable_questions_from_category(
|
||||
$questionids = question_bank::get_qtype('random')->get_available_questions_from_category(
|
||||
$category->id, $question->questiontext == '1', '0');
|
||||
$questioncount = count($questionids);
|
||||
|
||||
@ -791,7 +840,7 @@ function quiz_print_randomquestion(&$question, &$pageurl, &$quiz, $quiz_qbanktoo
|
||||
echo '<br />';
|
||||
|
||||
// Embed the link into the string with instructions
|
||||
$a = new stdClass;
|
||||
$a = new stdClass();
|
||||
$a->catname = '<strong>' . $category->name . '</strong>';
|
||||
$a->link = $linkcategorycontents;
|
||||
echo get_string('addnewquestionsqbank', 'quiz', $a);
|
||||
@ -800,13 +849,9 @@ function quiz_print_randomquestion(&$question, &$pageurl, &$quiz, $quiz_qbanktoo
|
||||
// Category has questions
|
||||
|
||||
// Get a sample from the database,
|
||||
$toshow = array_slice($questionids, 0, NUM_QS_TO_SHOW_IN_RANDOM);
|
||||
$questionidstoshow = array();
|
||||
foreach ($toshow as $a) {
|
||||
$questionidstoshow[] = $a->id;
|
||||
}
|
||||
$questionidstoshow = array_slice($questionids, 0, NUM_QS_TO_SHOW_IN_RANDOM);
|
||||
$questionstoshow = $DB->get_records_list('question', 'id', $questionidstoshow,
|
||||
'', 'id,qtype,name,questiontext,questiontextformat');
|
||||
'', 'id, qtype, name, questiontext, questiontextformat');
|
||||
|
||||
// list them,
|
||||
echo '<ul>';
|
||||
@ -829,7 +874,6 @@ function quiz_print_randomquestion(&$question, &$pageurl, &$quiz, $quiz_qbanktoo
|
||||
echo '<div class="randomquestioncategorycount">';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -860,14 +904,15 @@ function quiz_print_singlequestion_reordertool($question, $returnurl, $quiz) {
|
||||
* @param object $quiz The quiz in the context of which the question is being displayed
|
||||
*/
|
||||
function quiz_print_randomquestion_reordertool(&$question, &$pageurl, &$quiz) {
|
||||
global $DB, $QTYPES, $OUTPUT;
|
||||
global $DB, $OUTPUT;
|
||||
|
||||
// Load the category, and the number of available questions in it.
|
||||
if (!$category = $DB->get_record('question_categories', array('id' => $question->category))) {
|
||||
echo $OUTPUT->notification('Random question category not found!');
|
||||
return;
|
||||
}
|
||||
$questioncount = count($QTYPES['random']->get_usable_questions_from_category(
|
||||
$questioncount = count(question_bank::get_qtype(
|
||||
'random')->get_available_questions_from_category(
|
||||
$category->id, $question->questiontext == '1', '0'));
|
||||
|
||||
$reordercheckboxlabel = '<label for="s' . $question->id . '">';
|
||||
@ -898,7 +943,6 @@ function quiz_print_randomquestion_reordertool(&$question, &$pageurl, &$quiz) {
|
||||
echo '<div class="randomquestioncategorycount">';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -916,30 +960,29 @@ function print_random_option_icon($question) {
|
||||
}
|
||||
echo '<img src="' . $OUTPUT->pix_url('i/' . $icon) . '" alt="' .
|
||||
$tooltip . '" title="' . $tooltip . '" class="uihint" />';
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a textual representation of a question for display.
|
||||
*
|
||||
* @param object $question A question object from the database questions table
|
||||
* @param boolean $showicon If true, show the question's icon with the question. False by default.
|
||||
* @param boolean $showquestiontext If true (default), show question text after question name.
|
||||
* @param bool $showicon If true, show the question's icon with the question. False by default.
|
||||
* @param bool $showquestiontext If true (default), show question text after question name.
|
||||
* If false, show only question name.
|
||||
* @param boolean $return If true (default), return the output. If false, print it.
|
||||
* @param bool $return If true (default), return the output. If false, print it.
|
||||
*/
|
||||
|
||||
function quiz_question_tostring(&$question, $showicon = false, $showquestiontext = true, $return = true) {
|
||||
function quiz_question_tostring($question, $showicon = false,
|
||||
$showquestiontext = true, $return = true) {
|
||||
global $COURSE;
|
||||
$result = '';
|
||||
$result .= '<span class="questionname">';
|
||||
if ($showicon) {
|
||||
$result .= print_question_icon($question, true);
|
||||
echo " ";
|
||||
echo ' ';
|
||||
}
|
||||
$result .= shorten_text(format_string($question->name), 200) . '</span>';
|
||||
if ($showquestiontext) {
|
||||
$formatoptions = new stdClass;
|
||||
$formatoptions = new stdClass();
|
||||
$formatoptions->noclean = true;
|
||||
$formatoptions->para = false;
|
||||
$questiontext = strip_tags(format_text($question->questiontext,
|
||||
@ -965,6 +1008,9 @@ function quiz_question_tostring(&$question, $showicon = false, $showquestiontext
|
||||
|
||||
/**
|
||||
* A column type for the add this question to the quiz.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class question_bank_add_to_quiz_action_column extends question_bank_action_column_base {
|
||||
protected $stradd;
|
||||
@ -995,6 +1041,9 @@ class question_bank_add_to_quiz_action_column extends question_bank_action_colum
|
||||
|
||||
/**
|
||||
* A column type for the name followed by the start of the question text.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class question_bank_question_name_text_column extends question_bank_question_name_column {
|
||||
public function get_name() {
|
||||
@ -1024,9 +1073,27 @@ class question_bank_question_name_text_column extends question_bank_question_nam
|
||||
|
||||
/**
|
||||
* Subclass to customise the view of the question bank for the quiz editing screen.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class quiz_question_bank_view extends question_bank_view {
|
||||
protected $quizhasattempts = false;
|
||||
/** @var object the quiz settings. */
|
||||
protected $quiz = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param question_edit_contexts $contexts
|
||||
* @param moodle_url $pageurl
|
||||
* @param object $course course settings
|
||||
* @param object $cm activity settings.
|
||||
* @param object $quiz quiz settings.
|
||||
*/
|
||||
public function __construct($contexts, $pageurl, $course, $cm, $quiz) {
|
||||
parent::__construct($contexts, $pageurl, $course, $cm);
|
||||
$this->quiz = $quiz;
|
||||
}
|
||||
|
||||
protected function known_field_types() {
|
||||
$types = parent::known_field_types();
|
||||
@ -1036,14 +1103,15 @@ class quiz_question_bank_view extends question_bank_view {
|
||||
}
|
||||
|
||||
protected function wanted_columns() {
|
||||
return array('addtoquizaction', 'checkbox', 'qtype', 'questionnametext', 'editaction', 'previewaction');
|
||||
return array('addtoquizaction', 'checkbox', 'qtype', 'questionnametext',
|
||||
'editaction', 'previewaction');
|
||||
}
|
||||
|
||||
/**
|
||||
* Let the question bank display know whether the quiz has been attempted,
|
||||
* hence whether some bits of UI, like the add this question to the quiz icon,
|
||||
* should be displayed.
|
||||
* @param boolean $quizhasattempts whether the quiz has attempts.
|
||||
* @param bool $quizhasattempts whether the quiz has attempts.
|
||||
*/
|
||||
public function set_quiz_has_attempts($quizhasattempts) {
|
||||
$this->quizhasattempts = $quizhasattempts;
|
||||
@ -1052,9 +1120,8 @@ class quiz_question_bank_view extends question_bank_view {
|
||||
}
|
||||
}
|
||||
|
||||
public function preview_question_url($questionid) {
|
||||
global $CFG;
|
||||
return $CFG->wwwroot . '/question/preview.php?id=' . $questionid . $this->quizorcourseid;
|
||||
public function preview_question_url($question) {
|
||||
return quiz_question_preview_url($this->quiz, $question);
|
||||
}
|
||||
|
||||
public function add_to_quiz_url($questionid) {
|
||||
@ -1084,8 +1151,9 @@ class quiz_question_bank_view extends question_bank_view {
|
||||
$this->baseurl, $cat);
|
||||
|
||||
// continues with list of questions
|
||||
$this->display_question_list($this->contexts->having_one_edit_tab_cap($tabname), $this->baseurl, $cat, $this->cm,
|
||||
$recurse, $page, $perpage, $showhidden, $sortorder, $sortorderdecoded, $showquestiontext,
|
||||
$this->display_question_list($this->contexts->having_one_edit_tab_cap($tabname),
|
||||
$this->baseurl, $cat, $this->cm, $recurse, $page,
|
||||
$perpage, $showhidden, $sortorder, $sortorderdecoded, $showquestiontext,
|
||||
$this->contexts->having_cap('moodle/question:add'));
|
||||
|
||||
$this->display_options($recurse, $showhidden, $showquestiontext);
|
||||
@ -1095,7 +1163,8 @@ class quiz_question_bank_view extends question_bank_view {
|
||||
protected function print_choose_category_message($categoryandcontext) {
|
||||
global $OUTPUT;
|
||||
echo $OUTPUT->box_start('generalbox questionbank');
|
||||
$this->display_category_form($this->contexts->having_one_edit_tab_cap('edit'), $this->baseurl, $categoryandcontext);
|
||||
$this->display_category_form($this->contexts->having_one_edit_tab_cap('edit'),
|
||||
$this->baseurl, $categoryandcontext);
|
||||
echo "<p style=\"text-align:center;\"><b>";
|
||||
print_string('selectcategoryabove', 'quiz');
|
||||
echo "</b></p>";
|
||||
@ -1103,27 +1172,32 @@ class quiz_question_bank_view extends question_bank_view {
|
||||
}
|
||||
|
||||
protected function print_category_info($category) {
|
||||
$formatoptions = new stdClass;
|
||||
$formatoptions = new stdClass();
|
||||
$formatoptions->noclean = true;
|
||||
$strcategory = get_string('category', 'quiz');
|
||||
echo '<div class="categoryinfo"><div class="categorynamefieldcontainer">' .
|
||||
$strcategory;
|
||||
echo ': <span class="categorynamefield">';
|
||||
echo shorten_text(strip_tags(format_text($category->name, FORMAT_MOODLE,
|
||||
$formatoptions, $this->course->id)), 60);
|
||||
echo '</span></div><div class="categoryinfofieldcontainer"><span class="categoryinfofield">';
|
||||
echo shorten_text(strip_tags(format_text($category->info, FORMAT_MOODLE,
|
||||
echo shorten_text(strip_tags(format_string($category->name)), 60);
|
||||
echo '</span></div><div class="categoryinfofieldcontainer">' .
|
||||
'<span class="categoryinfofield">';
|
||||
echo shorten_text(strip_tags(format_text($category->info, $category->infoformat,
|
||||
$formatoptions, $this->course->id)), 200);
|
||||
echo '</span></div></div>';
|
||||
}
|
||||
|
||||
protected function display_options($recurse = 1, $showhidden = false, $showquestiontext = false) {
|
||||
protected function display_options($recurse = 1, $showhidden = false,
|
||||
$showquestiontext = false) {
|
||||
echo '<form method="get" action="edit.php" id="displayoptions">';
|
||||
echo "<fieldset class='invisiblefieldset'>";
|
||||
echo html_writer::input_hidden_params($this->baseurl, array('recurse', 'showhidden', 'showquestiontext'));
|
||||
$this->display_category_form_checkbox('recurse', get_string('recurse', 'quiz'));
|
||||
$this->display_category_form_checkbox('showhidden', get_string('showhidden', 'quiz'));
|
||||
echo '<noscript><div class="centerpara"><input type="submit" value="'. get_string('go') . '" />';
|
||||
echo html_writer::input_hidden_params($this->baseurl,
|
||||
array('recurse', 'showhidden', 'showquestiontext'));
|
||||
$this->display_category_form_checkbox('recurse',
|
||||
get_string('includesubcategories', 'question'));
|
||||
$this->display_category_form_checkbox('showhidden',
|
||||
get_string('showhidden', 'question'));
|
||||
echo '<noscript><div class="centerpara"><input type="submit" value="' .
|
||||
get_string('go') . '" />';
|
||||
echo '</div></noscript></fieldset></form>';
|
||||
}
|
||||
}
|
||||
@ -1134,18 +1208,19 @@ class quiz_question_bank_view extends question_bank_view {
|
||||
* @param object $quiz The quiz object of the quiz in question
|
||||
* @param object $pageurl The url of the current page with the parameters required
|
||||
* for links returning to the current page, as a moodle_url object
|
||||
* @param integer $tabindex The tabindex to start from for the form elements created
|
||||
* @return integer The tabindex from which the calling page can continue, that is,
|
||||
* @param int $tabindex The tabindex to start from for the form elements created
|
||||
* @return int The tabindex from which the calling page can continue, that is,
|
||||
* the last value used +1.
|
||||
*/
|
||||
function quiz_print_grading_form($quiz, $pageurl, $tabindex) {
|
||||
global $USER, $OUTPUT;
|
||||
$strsave = get_string('save', 'quiz');
|
||||
echo "<form method=\"post\" action=\"edit.php\"><div>";
|
||||
echo '<form method="post" action="edit.php" class="quizsavegradesform"><div>';
|
||||
echo '<fieldset class="invisiblefieldset" style="display: block;">';
|
||||
echo "<input type=\"hidden\" name=\"sesskey\" value=\"" . sesskey() . "\" />";
|
||||
echo html_writer::input_hidden_params($pageurl);
|
||||
$a = '<input type="text" id="inputmaxgrade" name="maxgrade" size="' . ($quiz->decimalpoints + 2) . '" tabindex="' . $tabindex
|
||||
$a = '<input type="text" id="inputmaxgrade" name="maxgrade" size="' .
|
||||
($quiz->decimalpoints + 2) . '" tabindex="' . $tabindex
|
||||
. '" value="' . quiz_format_grade($quiz, $quiz->grade) . '" />';
|
||||
echo '<label for="inputmaxgrade">' . get_string('maximumgradex', '', $a) . "</label>";
|
||||
echo '<input type="hidden" name="savechanges" value="save" />';
|
||||
@ -1164,14 +1239,14 @@ function quiz_print_status_bar($quiz) {
|
||||
global $CFG;
|
||||
$numberofquestions = quiz_number_of_questions_in_quiz($quiz->questions);
|
||||
?><div class="statusbar"><span class="totalpoints">
|
||||
<?php echo get_string('totalpointsx', 'quiz', quiz_format_grade($quiz, $quiz->sumgrades)) ?></span>
|
||||
<?php echo get_string('totalpointsx', 'quiz',
|
||||
quiz_format_grade($quiz, $quiz->sumgrades)) ?></span>
|
||||
| <span class="numberofquestions">
|
||||
<?php
|
||||
echo get_string('numquestionsx', 'quiz', $numberofquestions);
|
||||
?></span>
|
||||
<?php
|
||||
|
||||
// Current status of the quiz, with open an close dates as a tool tip.
|
||||
// Current status of the quiz, with open an close dates as a tool tip.
|
||||
$currentstatus = get_string('quizisopen', 'quiz');
|
||||
$dates = array();
|
||||
$timenow = time();
|
||||
@ -1189,7 +1264,8 @@ function quiz_print_status_bar($quiz) {
|
||||
print_string('quizisclosed', 'quiz');
|
||||
} else {
|
||||
$dates[] = get_string('quizcloseson', 'quiz', userdate($quiz->timeclose));
|
||||
$currentstatus = get_string('quizisopenwillclose', 'quiz', userdate($quiz->timeclose, get_string('strftimedatetimeshort', 'langconfig')));
|
||||
$currentstatus = get_string('quizisopenwillclose', 'quiz',
|
||||
userdate($quiz->timeclose, get_string('strftimedatetimeshort', 'langconfig')));
|
||||
}
|
||||
}
|
||||
if (empty($dates)) {
|
||||
@ -1202,5 +1278,3 @@ function quiz_print_status_bar($quiz) {
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -1,27 +1,52 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
require_once("../../config.php");
|
||||
/**
|
||||
* This page is the entry page into the quiz UI. Displays information about the
|
||||
* quiz to students and teachers, and lets students see their previous attempts.
|
||||
*
|
||||
* @package mod
|
||||
* @subpackage quiz
|
||||
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$id = required_param('id', PARAM_INT); // Course module ID
|
||||
|
||||
if (! $cm = get_coursemodule_from_id('quiz', $id)) {
|
||||
require_once(dirname(__FILE__) . '/../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
|
||||
|
||||
|
||||
$id = required_param('id', PARAM_INT);
|
||||
|
||||
if (!$cm = get_coursemodule_from_id('quiz', $id)) {
|
||||
print_error('invalidcoursemodule');
|
||||
}
|
||||
|
||||
if (! $quiz = $DB->get_record('quiz', array('id' => $cm->instance))) {
|
||||
}
|
||||
if (!$quiz = $DB->get_record('quiz', array('id' => $cm->instance))) {
|
||||
print_error('invalidquizid');
|
||||
}
|
||||
|
||||
if (! $course = $DB->get_record('course', array('id' => $quiz->course))) {
|
||||
}
|
||||
if (!$course = $DB->get_record('course', array('id' => $quiz->course))) {
|
||||
print_error('coursemisconf');
|
||||
}
|
||||
|
||||
require_login($course->id, false, $cm);
|
||||
|
||||
if (has_capability('mod/quiz:viewreports', get_context_instance(CONTEXT_MODULE, $cm->id))) {
|
||||
redirect('report.php?id='.$cm->id);
|
||||
} else {
|
||||
redirect('view.php?id='.$cm->id);
|
||||
}
|
||||
}
|
||||
|
||||
require_login($course, false, $cm);
|
||||
|
||||
$reportlist = quiz_report_list(get_context_instance(CONTEXT_MODULE, $cm->id));
|
||||
if (!empty($reportlist)) {
|
||||
redirect(new moodle_url('/mod/quiz/report.php', array(
|
||||
'id' => $cm->id, 'mode' => reset($reportlist))));
|
||||
} else {
|
||||
redirect(new moodle_url('/mod/quiz/view.php', array('id' => $cm->id)));
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user