mirror of
https://github.com/moodle/moodle.git
synced 2025-08-02 23:59:41 +02:00
merging MOODLE_19_QUESTIONS with HEAD
This commit is contained in:
parent
3bee1ead40
commit
271e6decda
47 changed files with 2807 additions and 1546 deletions
72
admin/report/question/index.php
Normal file
72
admin/report/question/index.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php // $Id$
|
||||
|
||||
require_once('../../../config.php');
|
||||
require_once($CFG->dirroot.'/question/upgrade.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
|
||||
admin_externalpage_setup('reportquestion');
|
||||
|
||||
admin_externalpage_print_header();
|
||||
print_heading(page_doc_link(get_string('adminreport', 'question')));
|
||||
|
||||
$probstr = '';
|
||||
if ($CFG->version < 2007081000){
|
||||
///cwrqpfs issue
|
||||
$probstr = print_heading(get_string('cwrqpfs', 'question'), '', 3, 'main', true);
|
||||
|
||||
if ($updates = question_cwqpfs_to_update()){
|
||||
|
||||
$probstr .=('<p>'.get_string('cwrqpfsinfo', 'question').'</p>');
|
||||
$probstr .= '<ul>';
|
||||
$catlist = join(array_keys($updates), ',');
|
||||
//get info about cateogries and no of questions used outside category's course
|
||||
$categories = get_records_sql('SELECT qc.*, c.fullname as coursename FROM '.$CFG->prefix.'question_categories as qc, '
|
||||
.$CFG->prefix.'course as c WHERE qc.course = c.id AND qc.id IN ('.$catlist.')');
|
||||
foreach ($updates as $id => $publish){
|
||||
$categories[$id]->caturl = "$CFG->wwwroot/question/category.php?sesskey=".sesskey().
|
||||
"&edit=$id&courseid=".$categories[$id]->course;
|
||||
if ($categories[$id]->publish){
|
||||
$categories[$id]->changefrom = get_string('published', 'question');
|
||||
$categories[$id]->changeto = get_string('unpublished', 'question');
|
||||
} else {
|
||||
$categories[$id]->changefrom = get_string('unpublished', 'question');
|
||||
$categories[$id]->changeto = get_string('published', 'question');
|
||||
}
|
||||
$probstr .= '<li>'.get_string('changepublishstatuscat', 'question', $categories[$id]);
|
||||
if ($questions = get_records_sql('SELECT q.*, qui.id as quizid, qui.name as quizname, cm.id as cmid, '
|
||||
.'qui.course, c.fullname as coursename FROM '.$CFG->prefix.'question as q, '
|
||||
.$CFG->prefix.'quiz_question_instances as qqi, '
|
||||
.$CFG->prefix.'quiz as qui, '
|
||||
.$CFG->prefix.'course_modules as cm, '
|
||||
.$CFG->prefix.'modules as m, '
|
||||
.$CFG->prefix.'course as c '
|
||||
.'WHERE (q.category = '.$id.' AND qqi.question = q.id '
|
||||
.'AND qqi.quiz = qui.id '
|
||||
.'AND qui.course = c.id '
|
||||
.'AND cm.instance = qui.id '
|
||||
.'AND cm.module = m.id '
|
||||
.'AND m.name = \'quiz\''
|
||||
.'AND ('.$categories[$id]->course.' <> qui.course)) ORDER BY qui.id ASC')){
|
||||
|
||||
$probstr .= '<ul>';
|
||||
foreach ($questions as $question){
|
||||
$question->quizurl = "$CFG->wwwroot/mod/quiz/edit.php?cmid=".$question->cmid;
|
||||
$question->qurl = "$CFG->wwwroot/question/question.php?cmid={$question->cmid}&id={$question->id}&returnurl=".urlencode($FULLME);
|
||||
$probstr .= '<li>'.get_string('questionaffected', 'question', $question).'</li>';
|
||||
}
|
||||
$probstr .= '</ul>';
|
||||
}
|
||||
$probstr .= '</li>';
|
||||
}
|
||||
$probstr .= '</ul>';
|
||||
} else {
|
||||
$probstr .=('<p>'.get_string('cwrqpfsnoprob', 'question').'</p>');
|
||||
}
|
||||
}
|
||||
if ($probstr) {
|
||||
print_box($probstr);
|
||||
} else {
|
||||
print_box(get_string('noprobs', 'question'), 'boxwidthnarrow boxaligncenter generalbox');
|
||||
}
|
||||
admin_externalpage_print_footer();
|
||||
?>
|
|
@ -799,28 +799,6 @@ $moodle_capabilities = array(
|
|||
)
|
||||
),
|
||||
|
||||
'moodle/question:import' => array(
|
||||
|
||||
'riskbitmask' => RISK_XSS,
|
||||
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'legacy' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'admin' => CAP_ALLOW
|
||||
)
|
||||
),
|
||||
|
||||
'moodle/question:export' => array(
|
||||
|
||||
'captype' => 'read',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'legacy' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'admin' => CAP_ALLOW
|
||||
)
|
||||
),
|
||||
|
||||
'moodle/question:managecategory' => array(
|
||||
|
||||
'captype' => 'write',
|
||||
|
@ -831,17 +809,92 @@ $moodle_capabilities = array(
|
|||
)
|
||||
),
|
||||
|
||||
'moodle/question:manage' => array(
|
||||
|
||||
'riskbitmask' => RISK_XSS,
|
||||
|
||||
//new in moodle 1.9
|
||||
'moodle/question:add' => array(
|
||||
'riskbitmask' => RISK_SPAM,
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'legacy' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'admin' => CAP_ALLOW
|
||||
)
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/question:manage'
|
||||
),
|
||||
'moodle/question:editmine' => array(
|
||||
'riskbitmask' => RISK_SPAM,
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'legacy' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'admin' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/question:manage'
|
||||
),
|
||||
'moodle/question:editall' => array(
|
||||
'riskbitmask' => RISK_SPAM,
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'legacy' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'admin' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/question:manage'
|
||||
),
|
||||
'moodle/question:viewmine' => array(
|
||||
'captype' => 'read',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'legacy' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'admin' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/question:manage'
|
||||
),
|
||||
'moodle/question:viewall' => array(
|
||||
'captype' => 'read',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'legacy' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'admin' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/question:manage'
|
||||
),
|
||||
'moodle/question:usemine' => array(
|
||||
'captype' => 'read',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'legacy' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'admin' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/question:manage'
|
||||
),
|
||||
'moodle/question:useall' => array(
|
||||
'captype' => 'read',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'legacy' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'admin' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/question:manage'
|
||||
),
|
||||
'moodle/question:movemine' => array(
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'legacy' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'admin' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/question:manage'
|
||||
),
|
||||
'moodle/question:moveall' => array(
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'legacy' => array(
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'admin' => CAP_ALLOW
|
||||
),
|
||||
'clonepermissionsfrom' => 'moodle/question:manage'
|
||||
),
|
||||
//END new in moodle 1.9
|
||||
|
||||
// Configure the installed question types.
|
||||
'moodle/question:config' => array(
|
||||
|
|
|
@ -975,7 +975,6 @@ function xmldb_main_upgrade($oldversion=0) {
|
|||
$result = $result && question_remove_rqp_qtype_config_string();
|
||||
}
|
||||
|
||||
|
||||
if ($result && $oldversion < 2007072200) {
|
||||
/// Remove obsoleted unit tests tables - they will be recreated automatically
|
||||
$tables = array('grade_categories',
|
||||
|
@ -1719,6 +1718,14 @@ function xmldb_main_upgrade($oldversion=0) {
|
|||
}
|
||||
}
|
||||
*/
|
||||
//need to change this when we merge with HEAD
|
||||
if ($result && $oldversion < 2007081000) {
|
||||
require_once($CFG->dirroot . '/question/upgrade.php');
|
||||
$result = $result && question_upgrade_context_etc();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
|
|
@ -2,20 +2,22 @@
|
|||
/**
|
||||
* A moodle form field type for question categories.
|
||||
*
|
||||
* @copyright © 2006 The Open University
|
||||
* @author T.J.Hunt@open.ac.uk
|
||||
* @copyright Jamie Pratt
|
||||
* @author Jamie Pratt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @package moodleforms
|
||||
*//** */
|
||||
*/
|
||||
|
||||
global $CFG;
|
||||
require_once("$CFG->libdir/form/select.php");
|
||||
require_once("$CFG->libdir/form/selectgroups.php");
|
||||
require_once("$CFG->libdir/questionlib.php");
|
||||
|
||||
/**
|
||||
* HTML class for a drop down element to select a question category.
|
||||
* @access public
|
||||
*/
|
||||
class MoodleQuickForm_questioncategory extends MoodleQuickForm_select {
|
||||
class MoodleQuickForm_questioncategory extends MoodleQuickForm_selectgroups {
|
||||
var $_options = array('top'=>false, 'currentcat'=>0, 'nochildrenof' => -1);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -28,45 +30,16 @@ class MoodleQuickForm_questioncategory extends MoodleQuickForm_select {
|
|||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function MoodleQuickForm_questioncategory($elementName = null,
|
||||
$elementLabel = null, $attributes = null, $options = null) {
|
||||
HTML_QuickForm_element::HTML_QuickForm_element($elementName, $elementLabel, $attributes, null);
|
||||
|
||||
global $COURSE;
|
||||
function MoodleQuickForm_questioncategory($elementName = null, $elementLabel = null, $options = null, $attributes = null) {
|
||||
MoodleQuickForm_selectgroups::MoodleQuickForm_selectgroups($elementName, $elementLabel, array(), $attributes);
|
||||
$this->_type = 'questioncategory';
|
||||
if (!empty($options['courseid'])) {
|
||||
$this->_courseid = $options['courseid'];
|
||||
} else {
|
||||
$this->_courseid = $COURSE->id;
|
||||
}
|
||||
if (!empty($options['published'])) {
|
||||
$this->_published = $options['published'];
|
||||
} else {
|
||||
$this->_published = false;
|
||||
}
|
||||
if (!empty($options['only_editable'])) {
|
||||
$this->_only_editable = $options['only_editable'];
|
||||
} else {
|
||||
$this->_only_editable = false;
|
||||
if (is_array($options)) {
|
||||
$this->_options = $options + $this->_options;
|
||||
$this->loadArrayOptGroups(
|
||||
question_category_options($this->_options['contexts'], $this->_options['top'], $this->_options['currentcat'],
|
||||
false, $this->_options['nochildrenof']));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by HTML_QuickForm whenever form event is made on this element
|
||||
*
|
||||
* @param string $event Name of event
|
||||
* @param mixed $arg event arguments
|
||||
* @param object $caller calling object
|
||||
* @access public
|
||||
* @return mixed
|
||||
*/
|
||||
function onQuickFormEvent($event, $arg, &$caller) {
|
||||
switch ($event) {
|
||||
case 'createElement':
|
||||
$this->load(question_category_options($this->_courseid, $this->_published, $this->_only_editable));
|
||||
break;
|
||||
}
|
||||
return parent::onQuickFormEvent($event, $arg, $caller);
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -29,27 +29,54 @@
|
|||
// When we backup a quiz we also need to backup the questions and possibly
|
||||
// the data about student interaction with the questions. The functions to do
|
||||
// that are included with the following library
|
||||
require_once("$CFG->libdir/questionlib.php");
|
||||
require_once("$CFG->dirroot/question/backuplib.php");
|
||||
|
||||
//STEP 1. Backup categories/questions and associated structures
|
||||
// (course independent)
|
||||
|
||||
//Insert necessary category ids to backup_ids table
|
||||
function insert_category_ids($course, $backup_unique_code, $instances = null) {
|
||||
/*
|
||||
* Insert necessary category ids to backup_ids table. Called during backup_check.html
|
||||
*/
|
||||
function insert_category_and_question_ids($course, $backup_unique_code, $instances = null) {
|
||||
global $CFG;
|
||||
include_once("$CFG->dirroot/mod/quiz/lib.php");
|
||||
|
||||
// Create missing categories and reasign orphaned questions.
|
||||
fix_orphaned_questions($course);
|
||||
// First, ALL categories from this course.
|
||||
// First, all categories from this course's context.
|
||||
$coursecontext = get_context_instance(CONTEXT_COURSE, $course);
|
||||
$status = execute_sql("INSERT INTO {$CFG->prefix}backup_ids
|
||||
(backup_code, table_name, old_id, info)
|
||||
SELECT '$backup_unique_code', 'question_categories', qc.id, ''
|
||||
FROM {$CFG->prefix}question_categories qc
|
||||
WHERE qc.course = $course", false);
|
||||
WHERE qc.contextid = {$coursecontext->id}", false);
|
||||
|
||||
// Then published categories from other courses used by the quizzes we are backing up.
|
||||
|
||||
// then, all categories from this course's modules' contexts.
|
||||
// using 'dummykeyname' in sql because otherwise get_records_sql_menu returns an error
|
||||
// if two key names are the same.
|
||||
$cmcontexts = get_records_sql_menu("SELECT c.id, c.id AS dummykeyname FROM `{$CFG->prefix}modules` AS `mod`,
|
||||
`{$CFG->prefix}course_modules` AS `cm`,
|
||||
`{$CFG->prefix}context` as `c`
|
||||
WHERE mod.name = 'quiz' AND mod.id = cm.module AND cm.id = c.instanceid
|
||||
AND c.contextlevel = ".CONTEXT_MODULE." AND cm.course = $course");
|
||||
if ($cmcontexts){
|
||||
$status = $status && execute_sql("INSERT INTO {$CFG->prefix}backup_ids
|
||||
(backup_code, table_name, old_id, info)
|
||||
SELECT '$backup_unique_code', 'question_categories', qc.id, ''
|
||||
FROM {$CFG->prefix}question_categories qc
|
||||
WHERE qc.contextid IN (".join(array_keys($cmcontexts), ', ').")", false);
|
||||
}
|
||||
//put the ids of the questions from all these categories into the db.
|
||||
$status = $status && execute_sql("INSERT INTO {$CFG->prefix}backup_ids
|
||||
(backup_code, table_name, old_id, info)
|
||||
SELECT '$backup_unique_code', 'question', q.id, ''
|
||||
FROM {$CFG->prefix}question AS q, {$CFG->prefix}backup_ids AS bk
|
||||
WHERE q.category = bk.old_id AND bk.table_name = 'question_categories' AND
|
||||
bk.backup_code = '$backup_unique_code'", false);
|
||||
|
||||
// Then categories from parent contexts used by the quizzes we are backing up.
|
||||
//TODO this will need generalising when we have modules other than quiz using shared questions above course level.
|
||||
$parentcontexts = get_parent_contexts($coursecontext);
|
||||
$from = "{$CFG->prefix}quiz quiz,";
|
||||
$where = "AND quiz.course = '$course'
|
||||
AND qqi.quiz = quiz.id";
|
||||
if (!empty($instances) && is_array($instances) && count($instances)) {
|
||||
$questionselectsqlfrom = '';
|
||||
$questionselectsqlwhere = 'AND qqi.quiz IN ('.implode(',',array_keys($instances)).')';
|
||||
|
@ -61,7 +88,7 @@
|
|||
$categoriesinothercourses = get_records_sql("
|
||||
SELECT id, parent, 0 AS childrendone
|
||||
FROM {$CFG->prefix}question_categories
|
||||
WHERE course <> $course
|
||||
WHERE contextid IN (".join($parentcontexts, ', ').")
|
||||
AND id IN (
|
||||
SELECT DISTINCT question.category
|
||||
FROM {$CFG->prefix}question question,
|
||||
|
@ -70,63 +97,90 @@
|
|||
WHERE qqi.question = question.id
|
||||
$questionselectsqlwhere
|
||||
)", false);
|
||||
if (!$categoriesinothercourses) {
|
||||
$categoriesinothercourses = array();
|
||||
}
|
||||
if (!$categories) {
|
||||
$categories = array();
|
||||
} else {
|
||||
//put the ids of the used questions from all these categories into the db.
|
||||
$status = $status && execute_sql("INSERT INTO {$CFG->prefix}backup_ids
|
||||
(backup_code, table_name, old_id, info)
|
||||
SELECT '$backup_unique_code', 'question', q.id, ''
|
||||
FROM {$CFG->prefix}question q,
|
||||
$from
|
||||
{$CFG->prefix}question_categories qc,
|
||||
{$CFG->prefix}quiz_question_instances qqi
|
||||
WHERE (qqi.question = q.id
|
||||
OR qqi.question = q.parent)
|
||||
AND q.category = qc.id
|
||||
AND qc.contextid IN (".join($parentcontexts, ', ').")
|
||||
$where", false);
|
||||
|
||||
// Add the parent categories, of these categories up to the top of the category tree.
|
||||
foreach ($categoriesinothercourses as $category) {
|
||||
while ($category->parent != 0) {
|
||||
if (array_key_exists($category->parent, $categoriesinothercourses)) {
|
||||
// Parent category already on the list.
|
||||
break;
|
||||
}
|
||||
$currentid = $category->id;
|
||||
$category = get_record('question_categories', 'id', $category->parent, '', '', '', '', 'id, parent, 0 AS childrendone');
|
||||
if ($category) {
|
||||
$categoriesinothercourses[$category->id] = $category;
|
||||
} else {
|
||||
// Parent not found: this indicates an error, but just fix it.
|
||||
set_field('question_categories', 'parent', 0, 'id', $currentid);
|
||||
break;
|
||||
// Add the parent categories, of these categories up to the top of the category tree.
|
||||
// not backing up the questions in these categories.
|
||||
foreach ($categories as $category) {
|
||||
while ($category->parent != 0) {
|
||||
if (array_key_exists($category->parent, $categories)) {
|
||||
// Parent category already on the list.
|
||||
break;
|
||||
}
|
||||
$currentid = $category->id;
|
||||
$category = get_record('question_categories', 'id', $category->parent, '', '', '', '', 'id, parent, 0 AS childrendone');
|
||||
if ($category) {
|
||||
$categories[$category->id] = $category;
|
||||
} else {
|
||||
// Parent not found: this indicates an error, but just fix it.
|
||||
set_field('question_categories', 'parent', 0, 'id', $currentid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now we look for random questions used in our quizzes
|
||||
// that select from subcategories in other courses. That implies
|
||||
// those subcategories also need to be backed up. (The categories themselves
|
||||
// and their parents will already have been included.)
|
||||
$categorieswithrandom = get_records_sql("
|
||||
SELECT DISTINCT question.category AS id
|
||||
FROM {$CFG->prefix}quiz_question_instances qqi,
|
||||
$questionselectsqlfrom
|
||||
{$CFG->prefix}question question
|
||||
WHERE question.id = qqi.question
|
||||
AND question.qtype = '" . RANDOM . "'
|
||||
AND question.questiontext = '1'
|
||||
$questionselectsqlwhere
|
||||
");
|
||||
if ($categorieswithrandom) {
|
||||
foreach ($categorieswithrandom as $category) {
|
||||
if (isset($categoriesinothercourses[$category->id])){
|
||||
$status = quiz_backup_add_sub_categories($categoriesinothercourses, $category->id);
|
||||
// Now we look for categories from other courses containing random questions
|
||||
// in our quizzes that select from the category and its subcategories. That implies
|
||||
// those subcategories also need to be backed up. (The categories themselves
|
||||
// and their parents will already have been included.)
|
||||
$categorieswithrandom = get_records_sql("
|
||||
SELECT question.category AS id, SUM(question.questiontext) as questiontext
|
||||
FROM {$CFG->prefix}quiz_question_instances qqi,
|
||||
$from
|
||||
{$CFG->prefix}question question
|
||||
WHERE question.id = qqi.question
|
||||
AND question.qtype = '" . RANDOM . "'
|
||||
$where
|
||||
GROUP BY question.category
|
||||
");
|
||||
$randomselectedquestions = array();
|
||||
if ($categorieswithrandom) {
|
||||
foreach ($categorieswithrandom as $category) {
|
||||
if ($category->questiontext){
|
||||
$status = $status && quiz_backup_add_sub_categories($categories, $randomselectedquestions, $category->id);
|
||||
}
|
||||
}
|
||||
$returnval = get_records_sql("
|
||||
SELECT question.id
|
||||
FROM {$CFG->prefix}question question
|
||||
WHERE question.category IN (".join(array_keys($categorieswithrandom), ', ').")");
|
||||
if ($returnval) {
|
||||
$randomselectedquestions += $returnval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, add all these extra categories to the backup_ids table.
|
||||
foreach ($categoriesinothercourses as $category) {
|
||||
$status = $status && backup_putid($backup_unique_code, 'question_categories', $category->id, 0);
|
||||
// Finally, add all these extra categories to the backup_ids table.
|
||||
foreach ($categories as $category) {
|
||||
$status = $status && backup_putid($backup_unique_code, 'question_categories', $category->id, 0);
|
||||
}
|
||||
// Finally, add all these extra categories to the backup_ids table.
|
||||
foreach ($randomselectedquestions as $question) {
|
||||
$status = $status && backup_putid($backup_unique_code, 'question', $question->id, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function adding the id of all the subcategories of a category to an array.
|
||||
*/
|
||||
function quiz_backup_add_sub_categories(&$categories, $categoryid) {
|
||||
function quiz_backup_add_sub_categories(&$categories, &$questions, $categoryid) {
|
||||
global $CFG;
|
||||
$status = true;
|
||||
if ($categories[$categoryid]->childrendone) {
|
||||
return $status;
|
||||
|
@ -136,7 +190,16 @@
|
|||
if (!array_key_exists($subcategory->id, $categories)) {
|
||||
$categories[$subcategory->id] = $subcategory;
|
||||
}
|
||||
$status = $status && quiz_backup_add_sub_categories($categories, $subcategory->id);
|
||||
$status = $status && quiz_backup_add_sub_categories($categories, $questions, $subcategory->id);
|
||||
}
|
||||
$subcatlist = join(array_keys($subcategories), ',');
|
||||
$returnval = get_records_sql("
|
||||
SELECT question.id
|
||||
FROM {$CFG->prefix}question question
|
||||
WHERE question.category IN ($subcatlist)
|
||||
");
|
||||
if ($returnval) {
|
||||
$questions += $returnval;
|
||||
}
|
||||
}
|
||||
$categories[$categoryid]->childrendone = 1;
|
||||
|
@ -166,10 +229,10 @@
|
|||
if (!$exist) {
|
||||
//Build a new category
|
||||
$db_cat = new stdClass;
|
||||
$db_cat->course = $course;
|
||||
// always create missing categories in course context
|
||||
$db_cat->contextid = get_context_instance(CONTEXT_COURSE, $course);
|
||||
$db_cat->name = get_string('recreatedcategory','',$key);
|
||||
$db_cat->info = get_string('recreatedcategory','',$key);
|
||||
$db_cat->publish = 1;
|
||||
$db_cat->stamp = make_unique_id_code();
|
||||
//Insert the new category
|
||||
$catid = insert_record('question_categories',$db_cat);
|
||||
|
@ -453,11 +516,14 @@
|
|||
////Return an array of info (name,value)
|
||||
/// $instances is an array with key = instanceid, value = object (name,id,userdata)
|
||||
function quiz_check_backup_mods($course,$user_data= false,$backup_unique_code,$instances=null) {
|
||||
|
||||
//Deletes data from mdl_backup_ids (categories section)
|
||||
delete_category_ids ($backup_unique_code);
|
||||
//Create date into mdl_backup_ids (categories section)
|
||||
insert_category_ids ($course,$backup_unique_code,$instances);
|
||||
delete_ids ($backup_unique_code, 'question_categories');
|
||||
delete_ids ($backup_unique_code, 'question');
|
||||
//this function selects all the questions / categories to be backed up.
|
||||
insert_category_and_question_ids($course, $backup_unique_code, $instances);
|
||||
if ($course != SITEID){
|
||||
question_insert_site_file_names($course, $backup_unique_code);
|
||||
}
|
||||
if (!empty($instances) && is_array($instances) && count($instances)) {
|
||||
$info = array();
|
||||
foreach ($instances as $id => $instance) {
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="mod/quiz/db" VERSION="20070228" COMMENT="XMLDB file for Moodle mod/quiz"
|
||||
<XMLDB PATH="mod/quiz/db" VERSION="20070522" COMMENT="XMLDB file for Moodle mod/quiz"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
<TABLES>
|
||||
<TABLE NAME="question_categories" COMMENT="Categories are for grouping questions" NEXT="question">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" ENUM="false" NEXT="course"/>
|
||||
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="id" NEXT="name"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="course" NEXT="info"/>
|
||||
<FIELD NAME="info" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="name" NEXT="publish"/>
|
||||
<FIELD NAME="publish" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="info" NEXT="stamp"/>
|
||||
<FIELD NAME="stamp" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="publish" NEXT="parent"/>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" ENUM="false" NEXT="name"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="id" NEXT="contextid"/>
|
||||
<FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="context that this category is shared in" PREVIOUS="name" NEXT="info"/>
|
||||
<FIELD NAME="info" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="contextid" NEXT="stamp"/>
|
||||
<FIELD NAME="stamp" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="info" NEXT="parent"/>
|
||||
<FIELD NAME="parent" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="stamp" NEXT="sortorder"/>
|
||||
<FIELD NAME="sortorder" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="999" SEQUENCE="false" ENUM="false" PREVIOUS="parent"/>
|
||||
</FIELDS>
|
||||
|
@ -20,7 +19,7 @@
|
|||
<KEY NAME="parent" TYPE="foreign" FIELDS="parent" REFTABLE="question_categories" REFFIELDS="id" COMMENT="note that to make this recursive FK working someday, the parent field must be declared NULL" PREVIOUS="primary"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="course" UNIQUE="false" FIELDS="course"/>
|
||||
<INDEX NAME="contextid" UNIQUE="false" FIELDS="contextid" COMMENT="links to context table"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="question" COMMENT="The questions themselves" PREVIOUS="question_categories" NEXT="question_answers">
|
||||
|
@ -39,12 +38,18 @@
|
|||
<FIELD NAME="length" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="1" SEQUENCE="false" ENUM="false" PREVIOUS="qtype" NEXT="stamp"/>
|
||||
<FIELD NAME="stamp" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="length" NEXT="version"/>
|
||||
<FIELD NAME="version" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" ENUM="false" PREVIOUS="stamp" NEXT="hidden"/>
|
||||
<FIELD NAME="hidden" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="version"/>
|
||||
<FIELD NAME="hidden" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" PREVIOUS="version" NEXT="timecreated"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="time question was created" PREVIOUS="hidden" NEXT="timemodified"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="time that question was last modified" PREVIOUS="timecreated" NEXT="createdby"/>
|
||||
<FIELD NAME="createdby" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="userid of person who created this question" PREVIOUS="timemodified" NEXT="modifiedby"/>
|
||||
<FIELD NAME="modifiedby" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="userid of person who last edited this question" PREVIOUS="createdby"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for question" NEXT="category"/>
|
||||
<KEY NAME="category" TYPE="foreign" FIELDS="category" REFTABLE="question_categories" REFFIELDS="id" PREVIOUS="primary" NEXT="parent"/>
|
||||
<KEY NAME="parent" TYPE="foreign" FIELDS="parent" REFTABLE="question" REFFIELDS="id" COMMENT="note that to make this recursive FK working someday, the parent field must be declared NULL" PREVIOUS="category"/>
|
||||
<KEY NAME="parent" TYPE="foreign" FIELDS="parent" REFTABLE="question" REFFIELDS="id" COMMENT="note that to make this recursive FK working someday, the parent field must be declared NULL" PREVIOUS="category" NEXT="createdby"/>
|
||||
<KEY NAME="createdby" TYPE="foreign" FIELDS="createdby" REFTABLE="user" REFFIELDS="id" COMMENT="foreign (createdby) references user (id)" PREVIOUS="parent" NEXT="modifiedby"/>
|
||||
<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_dataset_definitions">
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
function xmldb_quiz_upgrade($oldversion=0) {
|
||||
|
||||
global $CFG, $THEME, $db;
|
||||
global $CFG, $THEME;
|
||||
|
||||
$result = true;
|
||||
|
||||
|
|
|
@ -30,12 +30,12 @@
|
|||
require_once($CFG->dirroot.'/mod/quiz/editlib.php');
|
||||
|
||||
/**
|
||||
* Callback function called from question_list() function (which is called from showbank()
|
||||
* Callback function called from question_list() function (which is called from showbank())
|
||||
* Displays action icon as first action for each question.
|
||||
*/
|
||||
function module_specific_actions($pageurl, $questionid, $cmid){
|
||||
function module_specific_actions($pageurl, $questionid, $cmid, $canuse){
|
||||
global $CFG;
|
||||
if (has_capability("mod/quiz:manage", get_context_instance(CONTEXT_MODULE, $cmid))){
|
||||
if ($canuse){
|
||||
$straddtoquiz = get_string("addtoquiz", "quiz");
|
||||
$out = "<a title=\"$straddtoquiz\" href=\"edit.php?".$pageurl->get_query_string()."&addquestion=$questionid&sesskey=".sesskey()."\"><img
|
||||
src=\"$CFG->pixpath/t/moveleft.gif\" alt=\"$straddtoquiz\" /></a> ";
|
||||
|
@ -45,28 +45,24 @@
|
|||
}
|
||||
}
|
||||
/**
|
||||
* Callback function called from question_list() function (which is called from showbank()
|
||||
* Callback function called from question_list() function (which is called from showbank())
|
||||
* Displays button in form with checkboxes for each question.
|
||||
*/
|
||||
function module_specific_buttons($cmid){
|
||||
global $THEME;
|
||||
if (has_capability("mod/quiz:manage", get_context_instance(CONTEXT_MODULE, $cmid))){
|
||||
$straddtoquiz = get_string("addtoquiz", "quiz");
|
||||
$out = "<input type=\"submit\" name=\"add\" value=\"{$THEME->larrow} $straddtoquiz\" />\n";
|
||||
$out .= '</td><td>';
|
||||
return $out;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
$straddtoquiz = get_string("addtoquiz", "quiz");
|
||||
$out = "<input type=\"submit\" name=\"add\" value=\"{$THEME->larrow} $straddtoquiz\" />\n";
|
||||
echo '<br />';
|
||||
return $out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback function called from question_list() function (which is called from showbank()
|
||||
* Displays button in form with checkboxes for each question.
|
||||
* Callback function called from question_list() function (which is called from showbank())
|
||||
*/
|
||||
function module_specific_controls($totalnumber, $recurse, $categoryid, $cmid){
|
||||
if (has_capability("mod/quiz:manage", get_context_instance(CONTEXT_MODULE, $cmid))){
|
||||
function module_specific_controls($totalnumber, $recurse, $category, $cmid){
|
||||
$catcontext = get_context_instance_by_id($category->contextid);
|
||||
if (has_capability('moodle/question:useall', $catcontext)){
|
||||
for ($i = 1;$i <= min(10, $totalnumber); $i++) {
|
||||
$randomcount[$i] = $i;
|
||||
}
|
||||
|
@ -76,16 +72,16 @@
|
|||
$out = '<br />';
|
||||
$out .= get_string('addrandom', 'quiz', choose_from_menu($randomcount, 'randomcount', '1', '', '', '', true));
|
||||
$out .= '<input type="hidden" name="recurse" value="'.$recurse.'" />';
|
||||
$out .= "<input type=\"hidden\" name=\"categoryid\" value=\"$categoryid\" />";
|
||||
$out .= "<input type=\"hidden\" name=\"categoryid\" value=\"$category->id\" />";
|
||||
$out .= ' <input type="submit" name="addrandom" value="'. get_string('add') .'" />';
|
||||
$out .= helpbutton('random', get_string('random', 'quiz'), 'quiz', true, false, '', true);
|
||||
return $out;
|
||||
} else {
|
||||
return '';
|
||||
$out = '';
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
list($thispageurl, $courseid, $cmid, $cm, $quiz, $pagevars) = question_edit_setup(true);
|
||||
list($thispageurl, $contexts, $cmid, $cm, $quiz, $pagevars) = question_edit_setup('editq', true);
|
||||
|
||||
//these params are only passed from page request to request while we stay on this page
|
||||
//otherwise they would go in question_edit_setup
|
||||
|
@ -112,15 +108,14 @@
|
|||
if (! $course = get_record("course", "id", $quiz->course)) {
|
||||
error("This course doesn't exist");
|
||||
}
|
||||
$coursecontext = get_context_instance(CONTEXT_COURSE, $quiz->course);
|
||||
$quizcontext = get_context_instance(CONTEXT_MODULE, $quiz->cmid);
|
||||
|
||||
|
||||
// Log this visit.
|
||||
add_to_log($cm->course, 'quiz', 'editquestions',
|
||||
"view.php?id=$cm->id", "$quiz->id", $cm->id);
|
||||
|
||||
require_capability('mod/quiz:manage', $quizcontext);
|
||||
//you need mod/quiz:manage in addition to question capabilities to access this page.
|
||||
require_capability('mod/quiz:manage', $contexts->lowest());
|
||||
|
||||
if (isset($quiz->instance)
|
||||
&& empty($quiz->grades)){ // Construct an array to hold all the grades.
|
||||
|
@ -187,6 +182,8 @@
|
|||
if (! $category = get_record('question_categories', 'id', $categoryid)) {
|
||||
error('Category ID is incorrect');
|
||||
}
|
||||
$catcontext = get_context_instance_by_id($category->contextid);
|
||||
require_capability('moodle/question:useall', $catcontext);
|
||||
$category->name = addslashes($category->name);
|
||||
// find existing random questions in this category
|
||||
$random = RANDOM;
|
||||
|
@ -214,7 +211,7 @@
|
|||
if ($randomcreate > 0) {
|
||||
|
||||
$form->name = get_string('random', 'quiz') .' ('. $category->name .')';
|
||||
$form->category = $category->id;
|
||||
$form->category = "$category->id,$category->contextid";
|
||||
$form->questiontext = $recurse; // we use the questiontext field to store the info
|
||||
// on whether to include questions in subcategories
|
||||
$form->questiontextformat = 0;
|
||||
|
@ -246,7 +243,6 @@
|
|||
error('Could not save layout');
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['delete']) and confirm_sesskey()) { /// Remove a question from the quiz
|
||||
quiz_delete_quiz_question($_REQUEST['delete'], $quiz);
|
||||
}
|
||||
|
@ -296,18 +292,15 @@
|
|||
delete_records('quiz_attempts', 'preview', '1', 'quiz', $quiz->id);
|
||||
}
|
||||
|
||||
/// all commands have been dealt with, now print the page
|
||||
question_showbank_actions($thispageurl, $cm);
|
||||
|
||||
if (empty($quiz->category) or !record_exists('question_categories', 'id', $quiz->category)) {
|
||||
$category = get_default_question_category($course->id);
|
||||
$quiz->category = $category->id;
|
||||
}
|
||||
/// all commands have been dealt with, now print the page
|
||||
|
||||
// Print basic page layout.
|
||||
|
||||
if (isset($quiz->instance) and record_exists_select('quiz_attempts', "quiz = '$quiz->instance' AND preview = '0'")){
|
||||
// one column layout with table of questions used in this quiz
|
||||
$strupdatemodule = has_capability('moodle/course:manageactivities', $coursecontext)
|
||||
$strupdatemodule = has_capability('moodle/course:manageactivities', $contexts->lowest())
|
||||
? update_module_button($cm->id, $course->id, get_string('modulename', 'quiz'))
|
||||
: "";
|
||||
$navlinks = array();
|
||||
|
@ -329,9 +322,7 @@
|
|||
$a->attemptnum = count_records('quiz_attempts', 'quiz', $quiz->id, 'preview', 0);
|
||||
$a->studentnum = count_records_select('quiz_attempts', "quiz = '$quiz->id' AND preview = '0'", 'COUNT(DISTINCT userid)');
|
||||
$a->studentstring = $course->students;
|
||||
if (! $cm = get_coursemodule_from_instance("quiz", $quiz->instance, $course->id)) {
|
||||
error("Course Module ID was incorrect");
|
||||
}
|
||||
|
||||
echo "<div class=\"attemptsnotice\">\n";
|
||||
echo "<a href=\"report.php?mode=overview&id=$cm->id\">".get_string('numattempts', 'quiz', $a)."</a><br />".get_string("attemptsexist","quiz");
|
||||
echo "</div><br />\n";
|
||||
|
@ -347,7 +338,7 @@
|
|||
}
|
||||
|
||||
// two column layout with quiz info in left column
|
||||
$strupdatemodule = has_capability('moodle/course:manageactivities', $coursecontext)
|
||||
$strupdatemodule = has_capability('moodle/course:manageactivities', $contexts->lowest())
|
||||
? update_module_button($cm->id, $course->id, get_string('modulename', 'quiz'))
|
||||
: "";
|
||||
$navlinks = array();
|
||||
|
@ -377,7 +368,7 @@
|
|||
|
||||
echo '</td><td style="width:50%" valign="top">';
|
||||
|
||||
question_showbank($thispageurl, $cm, $pagevars['qpage'], $pagevars['qperpage'], $pagevars['qsortorder'], $pagevars['qsortorderdecoded'],
|
||||
question_showbank('editq', $contexts, $thispageurl, $cm, $pagevars['qpage'], $pagevars['qperpage'], $pagevars['qsortorder'], $pagevars['qsortorderdecoded'],
|
||||
$pagevars['cat'], $pagevars['recurse'], $pagevars['showhidden'], $pagevars['showquestiontext']);
|
||||
|
||||
echo '</td></tr>';
|
||||
|
|
|
@ -141,6 +141,7 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete=true, $showbreak
|
|||
$strgrade = get_string("grade");
|
||||
$strremove = get_string('remove', 'quiz');
|
||||
$stredit = get_string("edit");
|
||||
$strview = get_string("view");
|
||||
$straction = get_string("action");
|
||||
$strmoveup = get_string("moveup");
|
||||
$strmovedown = get_string("movedown");
|
||||
|
@ -155,7 +156,7 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete=true, $showbreak
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!$questions = get_records_sql("SELECT q.*,c.course
|
||||
if (!$questions = get_records_sql("SELECT q.*,c.contextid
|
||||
FROM {$CFG->prefix}question q,
|
||||
{$CFG->prefix}question_categories c
|
||||
WHERE q.id in ($quiz->questions)
|
||||
|
@ -169,7 +170,7 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete=true, $showbreak
|
|||
$count = 0;
|
||||
$qno = 1;
|
||||
$sumgrade = 0;
|
||||
$order = explode(",", $quiz->questions);
|
||||
$order = explode(',', $quiz->questions);
|
||||
$lastindex = count($order)-1;
|
||||
// If the list does not end with a pagebreak then add it on.
|
||||
if ($order[$lastindex] != 0) {
|
||||
|
@ -235,12 +236,11 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete=true, $showbreak
|
|||
echo '<td colspan="2"> </td>';
|
||||
}
|
||||
$count++;
|
||||
// missing </tr> here, if loop is broken, need to close the </tr> from line 199/201
|
||||
// missing </tr> here, if loop is broken, need to close the </tr>
|
||||
echo "</tr>";
|
||||
continue;
|
||||
}
|
||||
$question = $questions[$qnum];
|
||||
$canedit = has_capability('moodle/question:manage', get_context_instance(CONTEXT_COURSE, $question->course));
|
||||
|
||||
echo "<td>";
|
||||
if ($count != 0) {
|
||||
|
@ -276,17 +276,20 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete=true, $showbreak
|
|||
}
|
||||
echo '</td><td align="center">';
|
||||
|
||||
if ($question->qtype != 'random') {
|
||||
quiz_question_preview_button($quiz, $question);
|
||||
if (($question->qtype != 'random')){
|
||||
echo quiz_question_preview_button($quiz, $question);
|
||||
}
|
||||
if ($canedit) {
|
||||
$returnurl = $pageurl->out();
|
||||
$questionparams = array('returnurl' => $returnurl, 'cmid'=>$quiz->cmid, 'id' => $qnum);
|
||||
$questionurl = new moodle_url("$CFG->wwwroot/question/question.php", $questionparams);
|
||||
$returnurl = $pageurl->out();
|
||||
$questionparams = array('returnurl' => $returnurl, 'cmid'=>$quiz->cmid, 'id' => $question->id);
|
||||
$questionurl = new moodle_url("$CFG->wwwroot/question/question.php", $questionparams);
|
||||
if (question_has_capability_on($question, 'edit', $question->category) || question_has_capability_on($question, 'move', $question->category)) {
|
||||
echo "<a title=\"$stredit\" href=\"".$questionurl->out()."\">
|
||||
<img src=\"$CFG->pixpath/t/edit.gif\" class=\"iconsmall\" alt=\"$stredit\" /></a>";
|
||||
} elseif (question_has_capability_on($question, 'view', $question->category)){
|
||||
echo "<a title=\"$strview\" href=\"".$questionurl->out(false, array('id'=>$question->id))."\"><img
|
||||
src=\"$CFG->pixpath/i/info.gif\" alt=\"$strview\" /></a> ";
|
||||
}
|
||||
if ($allowdelete) {
|
||||
if ($allowdelete && question_has_capability_on($question, 'use', $question->category)) { // remove from quiz, not question delete.
|
||||
echo "<a title=\"$strremove\" href=\"".$pageurl->out_action(array('delete'=>$count))."\">
|
||||
<img src=\"$CFG->pixpath/t/removeright.gif\" class=\"iconsmall\" alt=\"$strremove\" /></a>";
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
// Print the header
|
||||
$strquizzes = get_string("modulenameplural", "quiz");
|
||||
$streditquestions = '';
|
||||
if (has_capability('moodle/question:manage', $coursecontext)) {
|
||||
$editqcontexts = new question_edit_contexts($coursecontext);
|
||||
if ($editqcontexts->have_one_edit_tab_cap('questions')) {
|
||||
$streditquestions =
|
||||
"<form target=\"_parent\" method=\"get\" action=\"$CFG->wwwroot/question/edit.php\">
|
||||
<div>
|
||||
|
|
|
@ -662,6 +662,9 @@ function quiz_upgrade_states($attempt) {
|
|||
*/
|
||||
function quiz_question_preview_button($quiz, $question) {
|
||||
global $CFG;
|
||||
if (!question_has_capability_on($question, 'use', $question->category)){
|
||||
return '';
|
||||
}
|
||||
$strpreview = get_string('previewquestion', 'quiz');
|
||||
return link_to_popup_window('/question/preview.php?id=' . $question->id . '&quizid=' . $quiz->id, 'questionpreview',
|
||||
"<img src=\"$CFG->pixpath/t/preview.gif\" class=\"iconsmall\" alt=\"$strpreview\" />",
|
||||
|
|
|
@ -16,12 +16,13 @@ if (!isset($currenttab)) {
|
|||
if (!isset($cm)) {
|
||||
$cm = get_coursemodule_from_instance('quiz', $quiz->id);
|
||||
}
|
||||
if (!isset($course)) {
|
||||
$course = get_record('course', 'id', $quiz->course);
|
||||
}
|
||||
|
||||
|
||||
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
|
||||
|
||||
if (!isset($contexts)){
|
||||
$contexts = new question_edit_contexts($context);
|
||||
}
|
||||
$tabs = array();
|
||||
$row = array();
|
||||
$inactive = array();
|
||||
|
@ -36,7 +37,7 @@ if (has_capability('mod/quiz:viewreports', $context)) {
|
|||
if (has_capability('mod/quiz:preview', $context)) {
|
||||
$row[] = new tabobject('preview', "$CFG->wwwroot/mod/quiz/attempt.php?q=$quiz->id", get_string('preview', 'quiz'));
|
||||
}
|
||||
if (has_capability('mod/quiz:manage', $context)) {
|
||||
if ($contexts->have_one_edit_tab_cap('editq')) {
|
||||
$row[] = new tabobject('edit', "$CFG->wwwroot/mod/quiz/edit.php?cmid=$cm->id", get_string('edit'));
|
||||
}
|
||||
|
||||
|
@ -83,9 +84,12 @@ if ($currenttab == 'edit' and isset($mode)) {
|
|||
$streditingquiz = get_string("editinga", "moodle", $strquiz);
|
||||
$strupdate = get_string('updatethis', 'moodle', $strquiz);
|
||||
|
||||
$row[] = new tabobject('editq', "$CFG->wwwroot/mod/quiz/edit.php?".$thispageurl->get_query_string(), $strquiz, $streditingquiz);
|
||||
questionbank_navigation_tabs($row, $context, $thispageurl->get_query_string());
|
||||
if ($contexts->have_one_edit_tab_cap('editq')) {
|
||||
$row[] = new tabobject('editq', "$CFG->wwwroot/mod/quiz/edit.php?".$thispageurl->get_query_string(), $strquiz, $streditingquiz);
|
||||
}
|
||||
questionbank_navigation_tabs($row, $contexts, $thispageurl->get_query_string());
|
||||
$tabs[] = $row;
|
||||
|
||||
}
|
||||
|
||||
print_tabs($tabs, $currenttab, $inactive, $activated);
|
||||
|
|
|
@ -77,6 +77,42 @@
|
|||
|
||||
require_once("$CFG->libdir/questionlib.php");
|
||||
|
||||
function backup_question_category_context($bf, $contextid, $course) {
|
||||
$status = true;
|
||||
$context = get_context_instance_by_id($contextid);
|
||||
$status = $status && fwrite($bf,start_tag("CONTEXT",4,true));
|
||||
switch ($context->contextlevel){
|
||||
case CONTEXT_MODULE:
|
||||
$status = $status && fwrite($bf,full_tag("LEVEL",5,false, 'module'));
|
||||
$status = $status && fwrite($bf,full_tag("INSTANCE",5,false, $context->instanceid));
|
||||
break;
|
||||
case CONTEXT_COURSE:
|
||||
$status = $status && fwrite($bf,full_tag("LEVEL",5,false, 'course'));
|
||||
break;
|
||||
case CONTEXT_COURSECAT:
|
||||
$thiscourse = get_record('course', 'id', $course);
|
||||
$cat = $thiscourse->category;
|
||||
$catno = 1;
|
||||
while($context->instanceid != $cat){
|
||||
$catno ++;
|
||||
if ($cat ==0) {
|
||||
return false;
|
||||
}
|
||||
$cat = get_field('course_categories', 'parent', 'id', $cat);
|
||||
}
|
||||
$status = $status && fwrite($bf,full_tag("LEVEL",5,false, 'coursecategory'));
|
||||
$status = $status && fwrite($bf,full_tag("COURSECATEGORYLEVEL",5,false, $catno));
|
||||
break;
|
||||
case CONTEXT_SYSTEM:
|
||||
$status = $status && fwrite($bf,full_tag("LEVEL",5,false, 'system'));
|
||||
break;
|
||||
default :
|
||||
return false;
|
||||
}
|
||||
$status = $status && fwrite($bf,end_tag("CONTEXT",4,true));
|
||||
return $status;
|
||||
}
|
||||
|
||||
function backup_question_categories($bf,$preferences) {
|
||||
|
||||
global $CFG;
|
||||
|
@ -89,28 +125,28 @@
|
|||
//If we've categories
|
||||
if ($categories) {
|
||||
//Write start tag
|
||||
$status = fwrite($bf,start_tag("QUESTION_CATEGORIES",2,true));
|
||||
$status = $status && fwrite($bf,start_tag("QUESTION_CATEGORIES",2,true));
|
||||
//Iterate over each category
|
||||
foreach ($categories as $cat) {
|
||||
//Start category
|
||||
$status = fwrite ($bf,start_tag("QUESTION_CATEGORY",3,true));
|
||||
$status = $status && fwrite ($bf,start_tag("QUESTION_CATEGORY",3,true));
|
||||
//Get category data from question_categories
|
||||
$category = get_record ("question_categories","id",$cat->old_id);
|
||||
//Print category contents
|
||||
fwrite($bf,full_tag("ID",4,false,$category->id));
|
||||
fwrite($bf,full_tag("NAME",4,false,$category->name));
|
||||
fwrite($bf,full_tag("INFO",4,false,$category->info));
|
||||
fwrite($bf,full_tag("PUBLISH",4,false,$category->publish));
|
||||
fwrite($bf,full_tag("STAMP",4,false,$category->stamp));
|
||||
fwrite($bf,full_tag("PARENT",4,false,$category->parent));
|
||||
fwrite($bf,full_tag("SORTORDER",4,false,$category->sortorder));
|
||||
$status = $status && fwrite($bf,full_tag("ID",4,false,$category->id));
|
||||
$status = $status && fwrite($bf,full_tag("NAME",4,false,$category->name));
|
||||
$status = $status && fwrite($bf,full_tag("INFO",4,false,$category->info));
|
||||
$status = $status && backup_question_category_context($bf, $category->contextid, $preferences->backup_course);
|
||||
$status = $status && fwrite($bf,full_tag("STAMP",4,false,$category->stamp));
|
||||
$status = $status && fwrite($bf,full_tag("PARENT",4,false,$category->parent));
|
||||
$status = $status && fwrite($bf,full_tag("SORTORDER",4,false,$category->sortorder));
|
||||
//Now, backup their questions
|
||||
$status = backup_question($bf,$preferences,$category->id);
|
||||
$status = $status && backup_question($bf,$preferences,$category->id);
|
||||
//End category
|
||||
$status = fwrite ($bf,end_tag("QUESTION_CATEGORY",3,true));
|
||||
$status = $status && fwrite ($bf,end_tag("QUESTION_CATEGORY",3,true));
|
||||
}
|
||||
//Write end tag
|
||||
$status = fwrite ($bf,end_tag("QUESTION_CATEGORIES",2,true));
|
||||
$status = $status && fwrite ($bf,end_tag("QUESTION_CATEGORIES",2,true));
|
||||
}
|
||||
|
||||
return $status;
|
||||
|
@ -127,16 +163,21 @@
|
|||
// We'll fetch the questions sorted by parent so that questions with no parents
|
||||
// (these are the ones which could be parents themselves) are backed up first. This
|
||||
// is important for the recoding of the parent field during the restore process
|
||||
$questions = get_records("question","category",$category,"parent ASC, id");
|
||||
// Only select questions with ids in backup_ids table
|
||||
$questions = get_records_sql("SELECT q.* FROM {$CFG->prefix}backup_ids bk, {$CFG->prefix}question q ".
|
||||
"WHERE q.category= $category AND ".
|
||||
"bk.old_id=q.id AND ".
|
||||
"bk.backup_code = {$preferences->backup_unique_code} ".
|
||||
"ORDER BY parent ASC, id");
|
||||
//If there are questions
|
||||
if ($questions) {
|
||||
//Write start tag
|
||||
$status = fwrite ($bf,start_tag("QUESTIONS",$level,true));
|
||||
$status = $status && fwrite ($bf,start_tag("QUESTIONS",$level,true));
|
||||
$counter = 0;
|
||||
//Iterate over each question
|
||||
foreach ($questions as $question) {
|
||||
//Start question
|
||||
$status = fwrite ($bf,start_tag("QUESTION",$level + 1,true));
|
||||
$status = $status && fwrite ($bf,start_tag("QUESTION",$level + 1,true));
|
||||
//Print question contents
|
||||
fwrite ($bf,full_tag("ID",$level + 2,false,$question->id));
|
||||
fwrite ($bf,full_tag("PARENT",$level + 2,false,$question->parent));
|
||||
|
@ -152,10 +193,14 @@
|
|||
fwrite ($bf,full_tag("STAMP",$level + 2,false,$question->stamp));
|
||||
fwrite ($bf,full_tag("VERSION",$level + 2,false,$question->version));
|
||||
fwrite ($bf,full_tag("HIDDEN",$level + 2,false,$question->hidden));
|
||||
fwrite ($bf,full_tag("TIMECREATED",$level + 2,false,$question->timecreated));
|
||||
fwrite ($bf,full_tag("TIMEMODIFIED",$level + 2,false,$question->timemodified));
|
||||
fwrite ($bf,full_tag("CREATEDBY",$level + 2,false,$question->createdby));
|
||||
fwrite ($bf,full_tag("MODIFIEDBY",$level + 2,false,$question->modifiedby));
|
||||
// Backup question type specific data
|
||||
$status = $QTYPES[$question->qtype]->backup($bf,$preferences,$question->id, $level + 2);
|
||||
$status = $status && $QTYPES[$question->qtype]->backup($bf,$preferences,$question->id, $level + 2);
|
||||
//End question
|
||||
$status = fwrite ($bf,end_tag("QUESTION",$level + 1,true));
|
||||
$status = $status && fwrite ($bf,end_tag("QUESTION",$level + 1,true));
|
||||
//Do some output
|
||||
$counter++;
|
||||
if ($counter % 10 == 0) {
|
||||
|
@ -167,7 +212,7 @@
|
|||
}
|
||||
}
|
||||
//Write end tag
|
||||
$status = fwrite ($bf,end_tag("QUESTIONS",$level,true));
|
||||
$status = $status && fwrite ($bf,end_tag("QUESTIONS",$level,true));
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
@ -183,18 +228,18 @@
|
|||
$answers = get_records("question_answers","question",$question,"id");
|
||||
//If there are answers
|
||||
if ($answers) {
|
||||
$status = fwrite ($bf,start_tag("ANSWERS",$level,true));
|
||||
$status = $status && fwrite ($bf,start_tag("ANSWERS",$level,true));
|
||||
//Iterate over each answer
|
||||
foreach ($answers as $answer) {
|
||||
$status = fwrite ($bf,start_tag("ANSWER",$level + 1,true));
|
||||
$status = $status && fwrite ($bf,start_tag("ANSWER",$level + 1,true));
|
||||
//Print answer contents
|
||||
fwrite ($bf,full_tag("ID",$level + 2,false,$answer->id));
|
||||
fwrite ($bf,full_tag("ANSWER_TEXT",$level + 2,false,$answer->answer));
|
||||
fwrite ($bf,full_tag("FRACTION",$level + 2,false,$answer->fraction));
|
||||
fwrite ($bf,full_tag("FEEDBACK",$level + 2,false,$answer->feedback));
|
||||
$status = fwrite ($bf,end_tag("ANSWER",$level + 1,true));
|
||||
$status = $status && fwrite ($bf,end_tag("ANSWER",$level + 1,true));
|
||||
}
|
||||
$status = fwrite ($bf,end_tag("ANSWERS",$level,true));
|
||||
$status = $status && fwrite ($bf,end_tag("ANSWERS",$level,true));
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
@ -209,17 +254,17 @@
|
|||
$numerical_units = get_records("question_numerical_units","question",$question,"id");
|
||||
//If there are numericals_units
|
||||
if ($numerical_units) {
|
||||
$status = fwrite ($bf,start_tag("NUMERICAL_UNITS",$level,true));
|
||||
$status = $status && fwrite ($bf,start_tag("NUMERICAL_UNITS",$level,true));
|
||||
//Iterate over each numerical_unit
|
||||
foreach ($numerical_units as $numerical_unit) {
|
||||
$status = fwrite ($bf,start_tag("NUMERICAL_UNIT",$level+1,true));
|
||||
$status = $status && fwrite ($bf,start_tag("NUMERICAL_UNIT",$level+1,true));
|
||||
//Print numerical_unit contents
|
||||
fwrite ($bf,full_tag("MULTIPLIER",$level+2,false,$numerical_unit->multiplier));
|
||||
fwrite ($bf,full_tag("UNIT",$level+2,false,$numerical_unit->unit));
|
||||
//Now backup numerical_units
|
||||
$status = fwrite ($bf,end_tag("NUMERICAL_UNIT",$level+1,true));
|
||||
$status = $status && fwrite ($bf,end_tag("NUMERICAL_UNIT",$level+1,true));
|
||||
}
|
||||
$status = fwrite ($bf,end_tag("NUMERICAL_UNITS",$level,true));
|
||||
$status = $status && fwrite ($bf,end_tag("NUMERICAL_UNITS",$level,true));
|
||||
}
|
||||
|
||||
return $status;
|
||||
|
@ -251,7 +296,7 @@
|
|||
fwrite ($bf,full_tag("OPTIONS",$level+2,false,$def->options));
|
||||
fwrite ($bf,full_tag("ITEMCOUNT",$level+2,false,$def->itemcount));
|
||||
//Now backup dataset_entries
|
||||
$status = question_backup_dataset_items($bf,$preferences,$def->id,$level+2);
|
||||
$status = $status && question_backup_dataset_items($bf,$preferences,$def->id,$level+2);
|
||||
//End dataset definition
|
||||
$status = $status &&fwrite ($bf,end_tag("DATASET_DEFINITION",$level+1,true));
|
||||
}
|
||||
|
@ -303,11 +348,11 @@
|
|||
//If there are states
|
||||
if ($question_states) {
|
||||
//Write start tag
|
||||
$status = fwrite ($bf,start_tag("STATES",$level,true));
|
||||
$status = $status && fwrite ($bf,start_tag("STATES",$level,true));
|
||||
//Iterate over each state
|
||||
foreach ($question_states as $state) {
|
||||
//Start state
|
||||
$status = fwrite ($bf,start_tag("STATE",$level + 1,true));
|
||||
$status = $status && fwrite ($bf,start_tag("STATE",$level + 1,true));
|
||||
//Print state contents
|
||||
fwrite ($bf,full_tag("ID",$level + 2,false,$state->id));
|
||||
fwrite ($bf,full_tag("QUESTION",$level + 2,false,$state->question));
|
||||
|
@ -320,10 +365,10 @@
|
|||
fwrite ($bf,full_tag("RAW_GRADE",$level + 2,false,$state->raw_grade));
|
||||
fwrite ($bf,full_tag("PENALTY",$level + 2,false,$state->penalty));
|
||||
//End state
|
||||
$status = fwrite ($bf,end_tag("STATE",$level + 1,true));
|
||||
$status = $status && fwrite ($bf,end_tag("STATE",$level + 1,true));
|
||||
}
|
||||
//Write end tag
|
||||
$status = fwrite ($bf,end_tag("STATES",$level,true));
|
||||
$status = $status && fwrite ($bf,end_tag("STATES",$level,true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -337,11 +382,11 @@
|
|||
//If there are sessions
|
||||
if ($question_sessions) {
|
||||
//Write start tag (the funny name 'newest states' has historical reasons)
|
||||
$status = fwrite ($bf,start_tag("NEWEST_STATES",$level,true));
|
||||
$status = $status && fwrite ($bf,start_tag("NEWEST_STATES",$level,true));
|
||||
//Iterate over each newest_state
|
||||
foreach ($question_sessions as $newest_state) {
|
||||
//Start newest_state
|
||||
$status = fwrite ($bf,start_tag("NEWEST_STATE",$level + 1,true));
|
||||
$status = $status && fwrite ($bf,start_tag("NEWEST_STATE",$level + 1,true));
|
||||
//Print newest_state contents
|
||||
fwrite ($bf,full_tag("ID",$level + 2,false,$newest_state->id));
|
||||
fwrite ($bf,full_tag("QUESTIONID",$level + 2,false,$newest_state->questionid));
|
||||
|
@ -350,10 +395,10 @@
|
|||
fwrite ($bf,full_tag("SUMPENALTY",$level + 2,false,$newest_state->sumpenalty));
|
||||
fwrite ($bf,full_tag("MANUALCOMMENT",$level + 2,false,$newest_state->manualcomment));
|
||||
//End newest_state
|
||||
$status = fwrite ($bf,end_tag("NEWEST_STATE",$level + 1,true));
|
||||
$status = $status && fwrite ($bf,end_tag("NEWEST_STATE",$level + 1,true));
|
||||
}
|
||||
//Write end tag
|
||||
$status = fwrite ($bf,end_tag("NEWEST_STATES",$level,true));
|
||||
$status = $status && fwrite ($bf,end_tag("NEWEST_STATES",$level,true));
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
@ -373,21 +418,44 @@
|
|||
|
||||
global $CFG;
|
||||
|
||||
return get_records_sql ("SELECT q.id, q.category
|
||||
FROM {$CFG->prefix}backup_ids a,
|
||||
{$CFG->prefix}question q
|
||||
WHERE a.backup_code = '$backup_unique_code' AND
|
||||
q.category = a.old_id AND
|
||||
a.table_name = 'question_categories'");
|
||||
return get_records_sql ("SELECT old_id, backup_code
|
||||
FROM {$CFG->prefix}backup_ids
|
||||
WHERE backup_code = '$backup_unique_code' AND
|
||||
table_name = 'question'");
|
||||
}
|
||||
|
||||
//Delete category ids from backup_ids table
|
||||
function delete_category_ids ($backup_unique_code) {
|
||||
function delete_ids ($backup_unique_code, $tablename) {
|
||||
global $CFG;
|
||||
$status = true;
|
||||
$status = execute_sql("DELETE FROM {$CFG->prefix}backup_ids
|
||||
WHERE backup_code = '$backup_unique_code'",false);
|
||||
WHERE backup_code = '$backup_unique_code' AND table_name = '$tablename'",false);
|
||||
return $status;
|
||||
}
|
||||
function question_insert_site_file_names($course, $backup_unique_code){
|
||||
global $QTYPES, $CFG;
|
||||
$status = true;
|
||||
$questionids = question_ids_by_backup ($backup_unique_code);
|
||||
$urls = array();
|
||||
if ($questionids){
|
||||
foreach ($questionids as $question_bk){
|
||||
$question = get_record('question', 'id', $question_bk->old_id);
|
||||
$QTYPES[$question->qtype]->get_question_options(&$question);
|
||||
$urls = array_merge_recursive($urls, $QTYPES[$question->qtype]->find_file_links($question, SITEID));
|
||||
}
|
||||
}
|
||||
ksort($urls);
|
||||
foreach (array_keys($urls) as $url){
|
||||
if (file_exists($CFG->dataroot.'/'.SITEID.'/'.$url)){
|
||||
$inserturl = new object();
|
||||
$inserturl->backup_code = $backup_unique_code;
|
||||
$inserturl->file_type = 'site';
|
||||
$url = clean_param($url, PARAM_PATH);
|
||||
$inserturl->path = addslashes($url);
|
||||
$status = $status && insert_record('backup_files', $inserturl);
|
||||
} else {
|
||||
notify(get_string('linkedfiledoesntexist', 'question', $url));
|
||||
}
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
@ -9,13 +9,12 @@
|
|||
*/
|
||||
|
||||
require_once("../config.php");
|
||||
require_once("editlib.php");
|
||||
require_once("category_class.php");
|
||||
require_once($CFG->dirroot."/question/editlib.php");
|
||||
require_once($CFG->dirroot."/question/category_class.php");
|
||||
|
||||
|
||||
|
||||
list($thispageurl, $courseid, $cmid, $cm, $module, $pagevars) = question_edit_setup();
|
||||
|
||||
list($thispageurl, $contexts, $cmid, $cm, $module, $pagevars) = question_edit_setup('categories');
|
||||
|
||||
// get values from form for actions on this page
|
||||
$param = new stdClass();
|
||||
|
@ -23,36 +22,64 @@
|
|||
|
||||
$param->moveup = optional_param('moveup', 0, PARAM_INT);
|
||||
$param->movedown = optional_param('movedown', 0, PARAM_INT);
|
||||
$param->moveupcontext = optional_param('moveupcontext', 0, PARAM_INT);
|
||||
$param->movedowncontext = optional_param('movedowncontext', 0, PARAM_INT);
|
||||
$param->tocontext = optional_param('tocontext', 0, PARAM_INT);
|
||||
$param->left = optional_param('left', 0, PARAM_INT);
|
||||
$param->right = optional_param('right', 0, PARAM_INT);
|
||||
$param->hide = optional_param('hide', 0, PARAM_INT);
|
||||
$param->delete = optional_param('delete', 0, PARAM_INT);
|
||||
$param->confirm = optional_param('confirm', 0, PARAM_INT);
|
||||
$param->cancel = optional_param('cancel', '', PARAM_ALPHA);
|
||||
$param->move = optional_param('move', 0, PARAM_INT);
|
||||
$param->moveto = optional_param('moveto', 0, PARAM_INT);
|
||||
$param->publish = optional_param('publish', 0, PARAM_INT);
|
||||
$param->addcategory = optional_param('addcategory', '', PARAM_NOTAGS);
|
||||
$param->edit = optional_param('edit', 0, PARAM_INT);
|
||||
$param->updateid = optional_param('updateid', 0, PARAM_INT);
|
||||
|
||||
if (! $course = get_record("course", "id", $courseid)) {
|
||||
error("Course ID is incorrect");
|
||||
}
|
||||
|
||||
$context = get_context_instance(CONTEXT_COURSE, $courseid);
|
||||
|
||||
require_capability('moodle/question:managecategory', $context);
|
||||
|
||||
$qcobject = new question_category_object($pagevars['cpage'], $thispageurl);
|
||||
$qcobject = new question_category_object($pagevars['cpage'], $thispageurl, $contexts->having_one_edit_tab_cap('categories'), $param->edit, $pagevars['cat'], $param->delete,
|
||||
$contexts->having_cap('moodle/question:add'));
|
||||
|
||||
$streditingcategories = get_string('editcategories', 'quiz');
|
||||
if ($qcobject->editlist->process_actions($param->left, $param->right, $param->moveup, $param->movedown)) {
|
||||
//processing of these actions is handled in the method and page redirects.
|
||||
} else if ($cm!==null) {
|
||||
if ($param->left || $param->right || $param->moveup || $param->movedown|| $param->moveupcontext || $param->movedowncontext){
|
||||
confirm_sesskey();
|
||||
foreach ($qcobject->editlists as $list){
|
||||
//processing of these actions is handled in the method where appropriate and page redirects.
|
||||
$list->process_actions($param->left, $param->right, $param->moveup, $param->movedown,
|
||||
$param->moveupcontext, $param->movedowncontext, $param->tocontext);
|
||||
}
|
||||
}
|
||||
if ($param->delete && ($questionstomove = count_records("question", "category", $param->delete))){
|
||||
if (!$category = get_record("question_categories", "id", $param->delete)) { // security
|
||||
error("No such category {$param->delete}!", $thispageurl->out());
|
||||
}
|
||||
$categorycontext = get_context_instance_by_id($category->contextid);
|
||||
$qcobject->moveform = new question_move_form($thispageurl,
|
||||
array('contexts'=>array($categorycontext), 'currentcat'=>$param->delete));
|
||||
if ($qcobject->moveform->is_cancelled()){
|
||||
redirect($thispageurl->out());
|
||||
} elseif ($formdata = $qcobject->moveform->get_data()) {
|
||||
/// 'confirm' is the category to move existing questions to
|
||||
$qcobject->move_questions_and_delete_category($formdata->delete, $formdata->category);
|
||||
redirect($thispageurl->out());
|
||||
}
|
||||
} else {
|
||||
$questionstomove = 0;
|
||||
}
|
||||
if ($qcobject->catform->is_cancelled()){
|
||||
redirect($thispageurl->out());
|
||||
}elseif ($catformdata = $qcobject->catform->get_data()) {
|
||||
if (!$catformdata->id) {//new category
|
||||
$qcobject->add_category($catformdata->parent, $catformdata->name, $catformdata->info);
|
||||
} else {
|
||||
$qcobject->update_category($catformdata->id, $catformdata->parent, $catformdata->name, $catformdata->info);
|
||||
}
|
||||
redirect($thispageurl->out());
|
||||
} elseif ((!empty($param->delete) and (!$questionstomove) and confirm_sesskey())) {
|
||||
$qcobject->delete_category($param->delete);//delete the category now no questions to move
|
||||
}
|
||||
$crumbs = array();
|
||||
if ($cm!==null) {
|
||||
// Page header
|
||||
$strupdatemodule = has_capability('moodle/course:manageactivities', get_context_instance(CONTEXT_COURSE, $course->id))
|
||||
? update_module_button($cm->id, $course->id, get_string('modulename', $cm->modname))
|
||||
$strupdatemodule = has_capability('moodle/course:manageactivities', $contexts->lowest())
|
||||
? update_module_button($cm->id, $COURSE->id, get_string('modulename', $cm->modname))
|
||||
: "";
|
||||
$navlinks = array();
|
||||
$navlinks[] = array('name' => get_string('modulenameplural', $cm->modname),
|
||||
|
@ -61,62 +88,42 @@
|
|||
$navlinks[] = array('name' => format_string($module->name),
|
||||
'link' => "$CFG->wwwroot/mod/{$cm->modname}/view.php?cmid={$cm->id}",
|
||||
'type' => 'title');
|
||||
} else {
|
||||
// Print basic page layout.
|
||||
$strupdatemodule = '';
|
||||
$navlinks = array();
|
||||
}
|
||||
|
||||
if (!$param->edit){
|
||||
$navlinks[] = array('name' => $streditingcategories, 'link' => '', 'type' => 'title');
|
||||
$navigation = build_navigation($navlinks);
|
||||
print_header_simple($streditingcategories, '', $navigation, "", "", true, $strupdatemodule);
|
||||
} else {
|
||||
$navlinks[] = array('name' => $streditingcategories, 'link' => $thispageurl->out(), 'type' => 'title');
|
||||
$navlinks[] = array('name' => get_string('editingcategory', 'question'), 'link' => '', 'type' => 'title');
|
||||
}
|
||||
|
||||
$navigation = build_navigation($navlinks);
|
||||
print_header_simple($streditingcategories, '', $navigation, "", "", true, $strupdatemodule);
|
||||
|
||||
// print tabs
|
||||
if ($cm!==null) {
|
||||
$currenttab = 'edit';
|
||||
$mode = 'categories';
|
||||
${$cm->modname} = $module;
|
||||
include($CFG->dirroot."/mod/{$cm->modname}/tabs.php");
|
||||
} else {
|
||||
// Print basic page layout.
|
||||
$navlinks = array();
|
||||
$navlinks[] = array('name' => $streditingcategories, 'link' => '', 'type' => 'title');
|
||||
$navigation = build_navigation($navlinks);
|
||||
|
||||
print_header_simple($streditingcategories, '', $navigation);
|
||||
|
||||
// print tabs
|
||||
$currenttab = 'categories';
|
||||
$context = $contexts->lowest();
|
||||
include('tabs.php');
|
||||
}
|
||||
|
||||
// Process actions.
|
||||
if (isset($_REQUEST['sesskey']) and confirm_sesskey()) { // sesskey must be ok
|
||||
if (!empty($param->delete) and empty($param->cancel)) {
|
||||
if (!empty($param->confirm)) {
|
||||
/// 'confirm' is the category to move existing questions to
|
||||
$qcobject->delete_category($param->delete, $param->confirm);
|
||||
} else {
|
||||
$qcobject->delete_category($param->delete);
|
||||
}
|
||||
} else if (!empty($param->hide)) {
|
||||
$qcobject->publish_category(false, $param->hide);
|
||||
} else if (!empty($param->publish)) {
|
||||
$qcobject->publish_category(true, $param->publish);
|
||||
} else if (!empty($param->addcategory)) {
|
||||
$param->newparent = required_param('newparent',PARAM_INT);
|
||||
$param->newcategory = required_param('newcategory',PARAM_NOTAGS);
|
||||
$param->newinfo = required_param('newinfo',PARAM_NOTAGS);
|
||||
$param->newpublish = required_param('newpublish',PARAM_INT);
|
||||
$qcobject->add_category($param->newparent, $param->newcategory, $param->newinfo,
|
||||
$param->newpublish, $course->id);
|
||||
} else if (!empty($param->edit)) {
|
||||
$qcobject->edit_single_category($param->edit, $pagevars['cpage']);
|
||||
} else if (!empty($param->updateid)) {
|
||||
$param->updateparent = required_param('updateparent',PARAM_INT);
|
||||
$param->updatename = required_param('updatename',PARAM_NOTAGS);
|
||||
$param->updateinfo = required_param('updateinfo',PARAM_NOTAGS);
|
||||
$param->updatepublish = required_param('updatepublish',PARAM_INT);
|
||||
$qcobject->update_category($param->updateid, $param->updateparent, $param->updatename,
|
||||
$param->updateinfo, $param->updatepublish, $course->id);
|
||||
}
|
||||
// display UI
|
||||
if (!empty($param->edit)) {
|
||||
$qcobject->edit_single_category($param->edit);
|
||||
} else if ($questionstomove){
|
||||
$qcobject->display_move_form($questionstomove, $category);
|
||||
} else {
|
||||
// display the user interface
|
||||
$qcobject->display_user_interface();
|
||||
}
|
||||
|
||||
// display the user interface
|
||||
$qcobject->display_user_interface();
|
||||
|
||||
print_footer($course);
|
||||
print_footer($COURSE);
|
||||
?>
|
||||
|
|
|
@ -8,64 +8,91 @@
|
|||
*/
|
||||
|
||||
// number of categories to display on page
|
||||
define("QUESTION_PAGE_LENGTH", 20);
|
||||
define("QUESTION_PAGE_LENGTH", 25);
|
||||
|
||||
require_once("$CFG->libdir/listlib.php");
|
||||
require_once("$CFG->dirroot/question/category_form.php");
|
||||
require_once('move_form.php');
|
||||
|
||||
class question_category_list extends moodle_list {
|
||||
var $table = "question_categories";
|
||||
var $listitemclassname = 'question_category_list_item';
|
||||
/**
|
||||
* @var reference to list displayed below this one.
|
||||
*/
|
||||
var $nextlist = null;
|
||||
/**
|
||||
* @var reference to list displayed above this one.
|
||||
*/
|
||||
var $lastlist = null;
|
||||
|
||||
var $context = null;
|
||||
|
||||
function question_category_list($type='ul', $attributes='', $editable = false, $pageurl=null, $page = 0, $pageparamname = 'page', $itemsperpage = 20, $context = null){
|
||||
parent::moodle_list('ul', '', $editable, $pageurl, $page, 'cpage', $itemsperpage);
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
function get_records() {
|
||||
global $COURSE, $CFG;
|
||||
$categories = get_records($this->table, 'course', "{$COURSE->id}", $this->sortby);
|
||||
|
||||
$catids = array_keys($categories);
|
||||
$select = "WHERE category IN ('".join("', '", $catids)."') AND hidden='0' AND parent='0'";
|
||||
$questioncounts = get_records_sql_menu('SELECT category, COUNT(*) FROM '. $CFG->prefix . 'question' .' '. $select.' GROUP BY category');
|
||||
foreach ($categories as $categoryid => $category){
|
||||
if (isset($questioncounts[$categoryid])){
|
||||
$categories[$categoryid]->questioncount = $questioncounts[$categoryid];
|
||||
} else {
|
||||
$categories[$categoryid]->questioncount = 0;
|
||||
$this->records = get_categories_for_contexts($this->context->id, $this->sortby);
|
||||
}
|
||||
function process_actions($left, $right, $moveup, $movedown, $moveupcontext, $movedowncontext, $tocontext){
|
||||
global $CFG;
|
||||
//parent::procces_actions redirects after any action
|
||||
parent::process_actions($left, $right, $moveup, $movedown);
|
||||
if ($tocontext == $this->context->id){
|
||||
//only called on toplevel list
|
||||
if ($moveupcontext){
|
||||
$cattomove = $moveupcontext;
|
||||
$totop = 0;
|
||||
} elseif ($movedowncontext){
|
||||
$cattomove = $movedowncontext;
|
||||
$totop = 1;
|
||||
}
|
||||
$toparent = "0,{$this->context->id}";
|
||||
redirect($CFG->wwwroot.'/question/contextmove.php?'.
|
||||
$this->pageurl->get_query_string(compact('cattomove', 'totop', 'toparent')));
|
||||
}
|
||||
$this->records = $categories;
|
||||
}
|
||||
}
|
||||
|
||||
class question_category_list_item extends list_item {
|
||||
|
||||
|
||||
function set_icon_html($first, $last, &$lastitem){
|
||||
global $CFG;
|
||||
$category = $this->item;
|
||||
$this->icons['edit']= $this->image_icon(get_string('editthiscategory'),
|
||||
"{$CFG->wwwroot}/question/category.php?".$this->parentlist->pageurl->get_query_string(array('edit'=>$category->id)), 'edit');
|
||||
parent::set_icon_html($first, $last, $lastitem);
|
||||
$toplevel = ($this->parentlist->parentitem === null);//this is a top level item
|
||||
if (($this->parentlist->nextlist !== null) && $last && $toplevel && (count($this->parentlist->items)>1)){
|
||||
$this->icons['down'] = $this->image_icon(get_string('shareincontext', 'question', print_context_name($this->parentlist->nextlist->context)),
|
||||
$this->parentlist->pageurl->out_action(array('movedowncontext'=>$this->id, 'tocontext'=>$this->parentlist->nextlist->context->id)), 'down');
|
||||
}
|
||||
if (($this->parentlist->lastlist !== null) && $first && $toplevel && (count($this->parentlist->items)>1)){
|
||||
$this->icons['up'] = $this->image_icon(get_string('shareincontext', 'question', print_context_name($this->parentlist->lastlist->context)),
|
||||
$this->parentlist->pageurl->out_action(array('moveupcontext'=>$this->id, 'tocontext'=>$this->parentlist->lastlist->context->id)), 'up');
|
||||
}
|
||||
}
|
||||
function item_html($extraargs = array()){
|
||||
global $CFG;
|
||||
$pixpath = $CFG->pixpath;
|
||||
$str = $extraargs['str'];
|
||||
$category = $this->item;
|
||||
|
||||
$linkcss = $category->publish ? ' class="published" ' : ' class="unpublished" ';
|
||||
|
||||
$editqestions = get_string('editquestions', 'quiz');
|
||||
|
||||
/// Each section adds html to be displayed as part of this list item
|
||||
|
||||
|
||||
$item = '<a ' . $linkcss . ' title="' . $str->edit. '" href="'.$this->parentlist->pageurl->out_action(array('edit'=>$this->id)).'">
|
||||
<img src="' . $pixpath . '/t/edit.gif" class="iconsmall"
|
||||
alt="' .$str->edit. '" /> ' . $category->name . '('.$category->questioncount.')'. '</a>';
|
||||
$questionbankurl = "{$CFG->wwwroot}/question/edit.php?".
|
||||
$this->parentlist->pageurl->get_query_string(array('category'=>"$category->id,$category->contextid"));
|
||||
$catediturl = $this->parentlist->pageurl->out(false, array('edit'=>$this->id));
|
||||
$item = "<a title=\"{$str->edit}\" href=\"$catediturl\">".$category->name ."</a> <a title=\"$editqestions\" href=\"$questionbankurl\">".'('.$category->questioncount.')</a>';
|
||||
|
||||
$item .= ' '. $category->info;
|
||||
|
||||
|
||||
if (!empty($category->publish)) {
|
||||
$item .= '<a title="' . $str->hide . '" href="'.$this->parentlist->pageurl->out_action(array('hide'=>$this->id)).'">
|
||||
<img src="' . $pixpath . '/t/hide.gif" class="iconsmall" alt="' .$str->hide. '" /></a> ';
|
||||
} else {
|
||||
$item .= '<a title="' . $str->publish . '" href="'.$this->parentlist->pageurl->out_action(array('publish'=>$this->id)).'">
|
||||
<img src="' . $pixpath . '/t/show.gif" class="iconsmall" alt="' .$str->publish. '" /></a> ';
|
||||
}
|
||||
|
||||
if ($category->id != $extraargs['defaultcategory']->id) {
|
||||
if (count($this->parentlist->records)!=1){ // don't allow delete if this is the last category in this context.
|
||||
$item .= '<a title="' . $str->delete . '" href="'.$this->parentlist->pageurl->out_action(array('delete'=>$this->id)).'">
|
||||
<img src="' . $pixpath . '/t/delete.gif" class="iconsmall" alt="' .$str->delete. '" /></a> ';
|
||||
}
|
||||
|
@ -88,29 +115,30 @@ class question_category_object {
|
|||
var $str;
|
||||
var $pixpath;
|
||||
/**
|
||||
* Nested list to display categories.
|
||||
* Nested lists to display categories.
|
||||
*
|
||||
* @var question_category_list
|
||||
* @var array
|
||||
*/
|
||||
var $editlist;
|
||||
var $editlists = array();
|
||||
var $newtable;
|
||||
var $tab;
|
||||
var $tabsize = 3;
|
||||
var $categories;
|
||||
var $categorystrings;
|
||||
var $defaultcategory;
|
||||
//------------------------------------------------------
|
||||
/**
|
||||
* @var moodle_url Object representing url for this page
|
||||
*/
|
||||
var $pageurl;
|
||||
/**
|
||||
* @var question_category_edit_form Object representing form for adding / editing categories.
|
||||
*/
|
||||
var $catform;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Gets necessary strings and sets relevant path information
|
||||
*/
|
||||
function question_category_object($page, $pageurl) {
|
||||
function question_category_object($page, $pageurl, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts) {
|
||||
global $CFG, $COURSE;
|
||||
|
||||
$this->tab = str_repeat(' ', $this->tabsize);
|
||||
|
@ -138,14 +166,38 @@ class question_category_object {
|
|||
$this->str->page = get_string('page');
|
||||
$this->pixpath = $CFG->pixpath;
|
||||
|
||||
$this->editlist = new question_category_list('ul', '', true, $pageurl, $page, 'cpage', QUESTION_PAGE_LENGTH);
|
||||
|
||||
$this->pageurl = $pageurl;
|
||||
|
||||
$this->initialize();
|
||||
$this->initialize($page, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Initializes this classes general category-related variables
|
||||
*/
|
||||
function initialize($page, $contexts, $currentcat, $defaultcategory, $todelete, $addcontexts) {
|
||||
$lastlist = null;
|
||||
foreach ($contexts as $context){
|
||||
$this->editlists[$context->id] = new question_category_list('ul', '', true, $this->pageurl, $page, 'cpage', QUESTION_PAGE_LENGTH, $context);
|
||||
$this->editlists[$context->id]->lastlist =& $lastlist;
|
||||
if ($lastlist!== null){
|
||||
$lastlist->nextlist =& $this->editlists[$context->id];
|
||||
}
|
||||
$lastlist =& $this->editlists[$context->id];
|
||||
}
|
||||
|
||||
$count = 1;
|
||||
$paged = false;
|
||||
foreach ($this->editlists as $key => $list){
|
||||
list($paged, $count) = $list->list_from_records($paged, $count);
|
||||
}
|
||||
$this->catform = new question_category_edit_form($this->pageurl, compact('contexts', 'currentcat'));
|
||||
if (!$currentcat){
|
||||
$this->catform->set_data(array('parent'=>$defaultcategory));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Displays the user interface
|
||||
*
|
||||
|
@ -153,91 +205,21 @@ class question_category_object {
|
|||
function display_user_interface() {
|
||||
|
||||
/// Interface for editing existing categories
|
||||
print_heading_with_help($this->str->editcategories, 'categories', 'quiz');
|
||||
$this->output_edit_list();
|
||||
$this->output_edit_lists();
|
||||
|
||||
|
||||
echo '<br />';
|
||||
/// Interface for adding a new category:
|
||||
print_heading_with_help($this->str->addcategory, 'categories_edit', 'quiz');
|
||||
$this->output_new_table();
|
||||
echo '<br />';
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes this classes general category-related variables
|
||||
*/
|
||||
function initialize() {
|
||||
global $COURSE, $CFG;
|
||||
|
||||
/// Get the existing categories
|
||||
if (!$this->defaultcategory = get_default_question_category($COURSE->id)) {
|
||||
error("Error: Could not find or make a category!");
|
||||
}
|
||||
|
||||
$this->editlist->list_from_records();
|
||||
|
||||
$this->categories = $this->editlist->records;
|
||||
|
||||
// create the array of id=>full_name strings
|
||||
$this->categorystrings = $this->expanded_category_strings($this->categories);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Outputs a table to allow entry of a new category
|
||||
*/
|
||||
function output_new_table() {
|
||||
global $USER, $COURSE;
|
||||
$publishoptions[0] = get_string("no");
|
||||
$publishoptions[1] = get_string("yes");
|
||||
|
||||
$this->newtable->head = array ($this->str->parent, $this->str->category, $this->str->categoryinfo, $this->str->publish, $this->str->action);
|
||||
$this->newtable->width = '200';
|
||||
$this->newtable->data[] = array();
|
||||
$this->newtable->tablealign = 'center';
|
||||
|
||||
/// Each section below adds a data cell to the table row
|
||||
|
||||
|
||||
$viableparents[0] = $this->str->top;
|
||||
$viableparents = $viableparents + $this->categorystrings;
|
||||
$this->newtable->align['parent'] = "left";
|
||||
$this->newtable->wrap['parent'] = "nowrap";
|
||||
$row['parent'] = choose_from_menu ($viableparents, "newparent", $this->str->top, "", "", "", true);
|
||||
|
||||
$this->newtable->align['category'] = "left";
|
||||
$this->newtable->wrap['category'] = "nowrap";
|
||||
$row['category'] = '<input type="text" name="newcategory" value="" size="15" />';
|
||||
|
||||
$this->newtable->align['info'] = "left";
|
||||
$this->newtable->wrap['info'] = "nowrap";
|
||||
$row['info'] = '<input type="text" name="newinfo" value="" size="50" />';
|
||||
|
||||
$this->newtable->align['publish'] = "left";
|
||||
$this->newtable->wrap['publish'] = "nowrap";
|
||||
$row['publish'] = choose_from_menu ($publishoptions, "newpublish", "", "", "", "", true);
|
||||
|
||||
$this->newtable->align['action'] = "left";
|
||||
$this->newtable->wrap['action'] = "nowrap";
|
||||
$row['action'] = '<input type="submit" value="' . $this->str->add . '" />';
|
||||
|
||||
|
||||
$this->newtable->data[] = $row;
|
||||
|
||||
// wrap the table in a form and output it
|
||||
echo '<form action="category.php" method="post">';
|
||||
echo '<fieldset class="invisiblefieldset" style="display: block">';
|
||||
echo "<input type=\"hidden\" name=\"sesskey\" value=\"$USER->sesskey\" />";
|
||||
echo $this->pageurl->hidden_params_out();
|
||||
echo '<input type="hidden" name="addcategory" value="true" />';
|
||||
print_table($this->newtable);
|
||||
echo '</fieldset>';
|
||||
echo '</form>';
|
||||
$this->catform->display();
|
||||
}
|
||||
|
||||
|
||||
|
@ -247,14 +229,19 @@ class question_category_object {
|
|||
* $this->initialize() must have already been called
|
||||
*
|
||||
*/
|
||||
function output_edit_list() {
|
||||
print_box_start('boxwidthwide boxaligncenter generalbox');
|
||||
echo $this->editlist->to_html(0, array('str'=>$this->str,
|
||||
'defaultcategory' => $this->defaultcategory));
|
||||
print_box_end();
|
||||
echo $this->editlist->display_page_numbers();
|
||||
|
||||
}
|
||||
function output_edit_lists() {
|
||||
print_heading_with_help(get_string('editcategories', 'quiz'), 'categories', 'quiz');
|
||||
foreach ($this->editlists as $context => $list){
|
||||
$listhtml = $list->to_html(0, array('str'=>$this->str));
|
||||
if ($listhtml){
|
||||
print_heading(get_string('questioncatsfor', 'question', print_context_name(get_context_instance_by_id($context))), '', 3);
|
||||
print_box_start('boxwidthwide boxaligncenter generalbox');
|
||||
echo $listhtml;
|
||||
print_box_end();
|
||||
}
|
||||
}
|
||||
echo $list->display_page_numbers();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -279,103 +266,20 @@ class question_category_object {
|
|||
|
||||
function edit_single_category($categoryid) {
|
||||
/// Interface for adding a new category
|
||||
global $CFG, $USER, $COURSE;
|
||||
|
||||
global $COURSE;
|
||||
/// Interface for editing existing categories
|
||||
if ($category = get_record("question_categories", "id", $categoryid)) {
|
||||
print_heading_with_help($this->str->edit, 'categories_edit', 'quiz');
|
||||
$this->output_edit_single_table($category);
|
||||
echo '<div class="centerpara">';
|
||||
print_single_button($CFG->wwwroot . '/question/category.php',
|
||||
$this->pageurl->params, $this->str->cancel);
|
||||
echo '</div>';
|
||||
print_footer($COURSE);
|
||||
exit;
|
||||
|
||||
$category->parent = "$category->parent,$category->contextid";
|
||||
$category->submitbutton = get_string('savechanges');
|
||||
$category->categoryheader = $this->str->edit;
|
||||
$this->catform->set_data($category);
|
||||
$this->catform->display();
|
||||
} else {
|
||||
error("Category $categoryid not found", "category.php?id={$COURSE->id}");
|
||||
error("Category $categoryid not found");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a table to allow editing of an existing category
|
||||
*
|
||||
* @param object category
|
||||
* @param int page current page
|
||||
*/
|
||||
function output_edit_single_table($category) {
|
||||
global $USER;
|
||||
$publishoptions[0] = get_string("no");
|
||||
$publishoptions[1] = get_string("yes");
|
||||
$strupdate = get_string('update');
|
||||
|
||||
$edittable = new stdClass;
|
||||
|
||||
$edittable->head = array ($this->str->parent, $this->str->category, $this->str->categoryinfo, $this->str->publish, $this->str->action);
|
||||
$edittable->width = 200;
|
||||
$edittable->data[] = array();
|
||||
$edittable->tablealign = 'center';
|
||||
|
||||
/// Each section below adds a data cell to the table row
|
||||
|
||||
$viableparents = $this->categorystrings;
|
||||
$this->set_viable_parents($viableparents, $category);
|
||||
$viableparents = array(0=>$this->str->top) + $viableparents;
|
||||
$edittable->align['parent'] = "left";
|
||||
$edittable->wrap['parent'] = "nowrap";
|
||||
$row['parent'] = choose_from_menu ($viableparents, "updateparent", "{$category->parent}", "", "", "", true);
|
||||
|
||||
$edittable->align['category'] = "left";
|
||||
$edittable->wrap['category'] = "nowrap";
|
||||
$row['category'] = '<input type="text" name="updatename" value="' . format_string($category->name) . '" size="15" />';
|
||||
|
||||
$edittable->align['info'] = "left";
|
||||
$edittable->wrap['info'] = "nowrap";
|
||||
$row['info'] = '<input type="text" name="updateinfo" value="' . $category->info . '" size="50" />';
|
||||
|
||||
$edittable->align['publish'] = "left";
|
||||
$edittable->wrap['publish'] = "nowrap";
|
||||
$selected = (boolean)$category->publish ? 1 : 0;
|
||||
$row['publish'] = choose_from_menu ($publishoptions, "updatepublish", $selected, "", "", "", true);
|
||||
|
||||
$edittable->align['action'] = "left";
|
||||
$edittable->wrap['action'] = "nowrap";
|
||||
$row['action'] = '<input type="submit" value="' . $strupdate . '" />';
|
||||
|
||||
$edittable->data[] = $row;
|
||||
|
||||
// wrap the table in a form and output it
|
||||
echo '<p><form action="category.php" method="post">';
|
||||
echo '<fieldset class="invisiblefieldset" style="display: block;">';
|
||||
echo '<input type="hidden" name="sesskey" value="' . $USER->sesskey . '" />';
|
||||
echo $this->pageurl->hidden_params_out();
|
||||
echo '<input type="hidden" name="updateid" value="' . $category->id . '" />';
|
||||
print_table($edittable);
|
||||
echo '</fieldset>';
|
||||
echo '</form></p>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of "full-path" category strings
|
||||
* Structure:
|
||||
* key => string
|
||||
* where key is the category id, and string contains the name of all ancestors as well as the particular category name
|
||||
* E.g. '123'=>'Language / English / Grammar / Modal Verbs"
|
||||
*
|
||||
* @param array $categories an array containing categories arranged in a tree structure
|
||||
*/
|
||||
function expanded_category_strings($categories, $parent=null) {
|
||||
$prefix = is_null($parent) ? '' : "$parent / ";
|
||||
$categorystrings = array();
|
||||
foreach ($categories as $key => $category) {
|
||||
$expandedname = "$prefix$category->name";
|
||||
$categorystrings[$key] = $expandedname;
|
||||
if (isset($category->children)) {
|
||||
$categorystrings = $categorystrings + $this->expanded_category_strings($category->children, $expandedname);
|
||||
}
|
||||
}
|
||||
return $categorystrings;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the viable parents
|
||||
|
@ -418,55 +322,16 @@ class question_category_object {
|
|||
* Deletes an existing question category
|
||||
*
|
||||
* @param int deletecat id of category to delete
|
||||
* @param int destcategoryid id of category which will inherit the orphans of deletecat
|
||||
*/
|
||||
function delete_category($deletecat, $destcategoryid = null) {
|
||||
global $USER, $COURSE;
|
||||
|
||||
if (!$category = get_record("question_categories", "id", $deletecat)) { // security
|
||||
error("No such category $deletecat!", "category.php?id={$COURSE->id}");
|
||||
function delete_category($categoryid) {
|
||||
global $CFG;
|
||||
question_can_delete_cat($categoryid);
|
||||
if (!$category = get_record("question_categories", "id", $categoryid)) { // security
|
||||
error("No such category $cat!", $this->pageurl->out());
|
||||
}
|
||||
|
||||
if (!is_null($destcategoryid)) { // Need to move some questions before deleting the category
|
||||
if (!$category2 = get_record("question_categories", "id", $destcategoryid)) { // security
|
||||
error("No such category $destcategoryid!", "category.php?id={$COURSE->id}");
|
||||
}
|
||||
if (! set_field('question', 'category', $destcategoryid, 'category', $deletecat)) {
|
||||
error("Error while moving questions from category '" . format_string($category->name) . "' to '$category2->name'", "category.php?id={$COURSE->id}");
|
||||
}
|
||||
|
||||
} else {
|
||||
// todo: delete any hidden questions that are not actually in use any more
|
||||
if ($count = count_records("question", "category", $category->id)) {
|
||||
$vars = new stdClass;
|
||||
$vars->name = $category->name;
|
||||
$vars->count = $count;
|
||||
print_simple_box(get_string("categorymove", "quiz", $vars), "center");
|
||||
$this->initialize();
|
||||
$categorystrings = $this->categorystrings;
|
||||
unset ($categorystrings[$category->id]);
|
||||
echo "<p><div align=\"center\"><form action=\"category.php\" method=\"get\">";
|
||||
echo '<fieldset class="invisiblefieldset">';
|
||||
echo "<input type=\"hidden\" name=\"sesskey\" value=\"$USER->sesskey\" />";
|
||||
echo "<input type=\"hidden\" name=\"id\" value=\"{$COURSE->id}\" />";
|
||||
echo "<input type=\"hidden\" name=\"delete\" value=\"$category->id\" />";
|
||||
choose_from_menu($categorystrings, "confirm", "", "");
|
||||
echo "<input type=\"submit\" value=\"". get_string("categorymoveto", "quiz") . "\" />";
|
||||
echo "<input type=\"submit\" name=\"cancel\" value=\"{$this->str->cancel}\" />";
|
||||
echo '</fieldset>';
|
||||
echo "</form></div></p>";
|
||||
print_footer($COURSE);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/// Send the children categories to live with their grandparent
|
||||
if ($childcats = get_records("question_categories", "parent", $category->id)) {
|
||||
foreach ($childcats as $childcat) {
|
||||
if (! set_field("question_categories", "parent", $category->parent, "id", $childcat->id)) {
|
||||
error("Could not update a child category!", "category.php?id={$COURSE->id}");
|
||||
}
|
||||
}
|
||||
if (!set_field("question_categories", "parent", $category->parent, "parent", $category->id)) {
|
||||
error("Could not update a child category!", $this->pageurl->out());
|
||||
}
|
||||
|
||||
/// Finally delete the category itself
|
||||
|
@ -475,64 +340,54 @@ class question_category_object {
|
|||
redirect($this->pageurl->out());//always redirect after successful action
|
||||
}
|
||||
}
|
||||
function move_questions_and_delete_category($oldcat, $newcat){
|
||||
question_can_delete_cat($oldcat);
|
||||
$this->move_questions($oldcat, $newcat);
|
||||
$this->delete_category($oldcat);
|
||||
}
|
||||
|
||||
function display_move_form($questionsincategory, $category){
|
||||
$vars = new stdClass;
|
||||
$vars->name = $category->name;
|
||||
$vars->count = $questionsincategory;
|
||||
print_simple_box(get_string("categorymove", "quiz", $vars), "center");
|
||||
$this->moveform->display();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes the published status of a category
|
||||
*
|
||||
* @param boolean publish
|
||||
* @param int categoryid
|
||||
*/
|
||||
function publish_category($publish, $categoryid) {
|
||||
/// Hide or publish a category
|
||||
|
||||
$publish = ($publish == false) ? 0 : 1;
|
||||
$tempcat = get_record("question_categories", "id", $categoryid);
|
||||
if ($tempcat) {
|
||||
if (! set_field("question_categories", "publish", $publish, "id", $tempcat->id)) {
|
||||
notify("Could not update that category!");
|
||||
} else {
|
||||
redirect($this->pageurl->out());//always redirect after successful action
|
||||
}
|
||||
|
||||
function move_questions($oldcat, $newcat){
|
||||
if (!set_field('question', 'category', $newcat, 'category', $oldcat)) {
|
||||
error("Error while moving questions from category '$oldcat' to '$newcat'", $this->pageurl->out());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new category with given params
|
||||
*
|
||||
* @param int $newparent id of the parent category
|
||||
* @param string $newcategory the name for the new category
|
||||
* @param string $newinfo the info field for the new category
|
||||
* @param int $newpublish whether to publish the category
|
||||
* @param int $newcourse the id of the associated course
|
||||
*/
|
||||
function add_category($newparent, $newcategory, $newinfo, $newpublish, $newcourse) {
|
||||
function add_category($newparent, $newcategory, $newinfo) {
|
||||
if (empty($newcategory)) {
|
||||
notify(get_string('categorynamecantbeblank', 'quiz'), 'notifyproblem');
|
||||
return false;
|
||||
error(get_string('categorynamecantbeblank', 'quiz'));
|
||||
}
|
||||
list($parentid, $contextid) = explode(',', $newparent);
|
||||
//moodle_form makes sure select element output is legal no need for further cleaning
|
||||
require_capability('moodle/question:managecategory', get_context_instance_by_id($contextid));
|
||||
|
||||
if ($newparent) {
|
||||
// first check that the parent category is in the correct course
|
||||
if(!(get_field('question_categories', 'course', 'id', $newparent) == $newcourse)) {
|
||||
return false;
|
||||
if ($parentid) {
|
||||
if(!(get_field('question_categories', 'contextid', 'id', $parentid) == $contextid)) {
|
||||
error("Could not insert the new question category '$newcategory' illegal contextid '$contextid'.");
|
||||
}
|
||||
}
|
||||
|
||||
$cat = NULL;
|
||||
$cat->parent = $newparent;
|
||||
$cat = new object();
|
||||
$cat->parent = $parentid;
|
||||
$cat->contextid = $contextid;
|
||||
$cat->name = $newcategory;
|
||||
$cat->info = $newinfo;
|
||||
$cat->publish = $newpublish;
|
||||
$cat->course = $newcourse;
|
||||
$cat->sortorder = 999;
|
||||
$cat->stamp = make_unique_id_code();
|
||||
if (!insert_record("question_categories", $cat)) {
|
||||
error("Could not insert the new question category '$newcategory'", "category.php?id={$newcourse}");
|
||||
error("Could not insert the new question category '$newcategory'");
|
||||
} else {
|
||||
notify(get_string("categoryadded", "quiz", $newcategory), 'notifysuccess');
|
||||
redirect($this->pageurl->out());//always redirect after successful action
|
||||
}
|
||||
}
|
||||
|
@ -540,32 +395,75 @@ class question_category_object {
|
|||
/**
|
||||
* Updates an existing category with given params
|
||||
*
|
||||
* @param int updateid
|
||||
* @param int updateparent
|
||||
* @param string updatename
|
||||
* @param string updateinfo
|
||||
* @param int updatepublish
|
||||
* @param int courseid the id of the associated course
|
||||
*/
|
||||
function update_category($updateid, $updateparent, $updatename, $updateinfo, $updatepublish, $courseid) {
|
||||
if (empty($updatename)) {
|
||||
notify(get_string('categorynamecantbeblank', 'quiz'), 'notifyproblem');
|
||||
return false;
|
||||
function update_category($updateid, $newparent, $newname, $newinfo) {
|
||||
global $CFG, $QTYPES;
|
||||
if (empty($newname)) {
|
||||
error(get_string('categorynamecantbeblank', 'quiz'));
|
||||
}
|
||||
|
||||
list($parentid, $tocontextid) = explode(',', $newparent);
|
||||
|
||||
$oldcat = get_record('question_categories', 'id', $updateid);
|
||||
$fromcontext = get_context_instance_by_id($oldcat->contextid);
|
||||
require_capability('moodle/question:managecategory', $fromcontext);
|
||||
if ($oldcat->contextid == $tocontextid){
|
||||
$tocontext = get_context_instance_by_id($tocontextid);
|
||||
require_capability('moodle/question:managecategory', $tocontext);
|
||||
}
|
||||
$cat = NULL;
|
||||
$cat->id = $updateid;
|
||||
$cat->parent = $updateparent;
|
||||
$cat->name = $updatename;
|
||||
$cat->info = $updateinfo;
|
||||
$cat->publish = $updatepublish;
|
||||
if (!update_record("question_categories", $cat)) {
|
||||
error("Could not update the category '$updatename'", "category.php?id={$courseid}");
|
||||
$cat->name = $newname;
|
||||
$cat->info = $newinfo;
|
||||
//never move category where it is the default
|
||||
if (1 != count_records_sql("SELECT count(*) FROM {$CFG->prefix}question_categories as c1, {$CFG->prefix}question_categories as c2 WHERE c2.id = $updateid AND c1.contextid = c2.contextid")){
|
||||
if ($oldcat->contextid == $tocontextid){ // not moving contexts
|
||||
$cat->parent = $parentid;
|
||||
if (!update_record("question_categories", $cat)) {
|
||||
error("Could not update the category '$newname'", $this->pageurl->out());
|
||||
} else {
|
||||
redirect($this->pageurl->out());
|
||||
}
|
||||
} else {
|
||||
if (!update_record("question_categories", $cat)) {
|
||||
error("Could not update the category '$newname'", $this->pageurl->out());
|
||||
} else {
|
||||
redirect($CFG->wwwroot.'/question/contextmove.php?'.
|
||||
$this->pageurl->get_query_string(array('cattomove' => $updateid,
|
||||
'toparent'=>$newparent)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
notify(get_string("categoryupdated", 'quiz'), 'notifysuccess');
|
||||
redirect($this->pageurl->out());
|
||||
error("Cannot move the category '$newname'. It is the last in this context.", $this->pageurl->out());
|
||||
}
|
||||
}
|
||||
|
||||
function move_question_from_cat_confirm($fromcat, $fromcourse, $tocat=null, $question=null){
|
||||
global $QTYPES;
|
||||
if (!$question){
|
||||
$questions[] = $question;
|
||||
} else {
|
||||
$questions = get_records('question', 'category', $tocat->id);
|
||||
}
|
||||
$urls = array();
|
||||
foreach ($questions as $question){
|
||||
$urls = array_merge($urls, $QTYPES[$question->qtype]->find_file_links_in_question($question));
|
||||
}
|
||||
if ($fromcourse){
|
||||
$append = 'tocourse';
|
||||
} else {
|
||||
$append = 'tosite';
|
||||
}
|
||||
if ($tocat){
|
||||
echo '<p>'.get_string('needtomovethesefilesincat','question').'</p>';
|
||||
} else {
|
||||
echo '<p>'.get_string('needtomovethesefilesinquestion','question').'</p>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
@ -14,18 +14,15 @@
|
|||
require_once("../config.php");
|
||||
require_once("editlib.php");
|
||||
|
||||
list($thispageurl, $courseid, $cmid, $cm, $module, $pagevars) = question_edit_setup();
|
||||
|
||||
if (! $course = get_record("course", "id", $courseid)) {
|
||||
error("This course doesn't exist");
|
||||
}
|
||||
$context = get_context_instance(CONTEXT_COURSE, $courseid);
|
||||
list($thispageurl, $contexts, $cmid, $cm, $module, $pagevars) = question_edit_setup('questions');
|
||||
|
||||
question_showbank_actions($thispageurl, $cm);
|
||||
|
||||
$context = $contexts->lowest();
|
||||
$streditingquestions = get_string('editquestions', "quiz");
|
||||
if ($cm!==null) {
|
||||
$strupdatemodule = has_capability('moodle/course:manageactivities', get_context_instance(CONTEXT_COURSE, $course->id))
|
||||
? update_module_button($cm->id, $course->id, get_string('modulename', $cm->modname))
|
||||
$strupdatemodule = has_capability('moodle/course:manageactivities', $contexts->lowest())
|
||||
? update_module_button($cm->id, $COURSE->id, get_string('modulename', $cm->modname))
|
||||
: "";
|
||||
$navlinks = array();
|
||||
$navlinks[] = array('name' => get_string('modulenameplural', $cm->modname), 'link' => "$CFG->wwwroot/mod/{$cm->modname}/index.php?id=$course->id", 'type' => 'activity');
|
||||
|
@ -55,11 +52,11 @@
|
|||
echo '<table class="boxaligncenter" border="0" cellpadding="2" cellspacing="0">';
|
||||
echo '<tr><td valign="top">';
|
||||
|
||||
question_showbank($thispageurl, $cm, $pagevars['qpage'], $pagevars['qperpage'], $pagevars['qsortorder'], $pagevars['qsortorderdecoded'],
|
||||
question_showbank('questions', $contexts, $thispageurl, $cm, $pagevars['qpage'], $pagevars['qperpage'], $pagevars['qsortorder'], $pagevars['qsortorderdecoded'],
|
||||
$pagevars['cat'], $pagevars['recurse'], $pagevars['showhidden'], $pagevars['showquestiontext']);
|
||||
|
||||
echo '</td></tr>';
|
||||
echo '</table>';
|
||||
|
||||
print_footer($course);
|
||||
print_footer($COURSE);
|
||||
?>
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
/**
|
||||
* Functions used to show question editing interface
|
||||
*
|
||||
* TODO: currently the function question_list still provides controls specific
|
||||
* to the quiz module. This needs to be generalised.
|
||||
*
|
||||
* @author Martin Dougiamas and many others. This has recently been extensively
|
||||
* rewritten by members of the Serving Mathematics project
|
||||
|
@ -78,53 +76,70 @@ function get_questions_category( $category, $noparent=false, $recurse=true, $exp
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the default category in a course
|
||||
* Gets the default category in the most specific context.
|
||||
* If no categories exist yet then default ones are created in all contexts.
|
||||
*
|
||||
* It returns the first category with no parent category. If no categories
|
||||
* exist yet then one is created.
|
||||
* @return object The default category
|
||||
* @param integer $courseid The id of the course whose default category is wanted
|
||||
* @param array $contexts The context objects for this context and all parent contexts.
|
||||
* @return object The default category - the category in the course context
|
||||
*/
|
||||
function get_default_question_category($courseid) {
|
||||
function question_make_default_categories($contexts) {
|
||||
// If it already exists, just return it.
|
||||
if ($category = get_records_select("question_categories", "course = '$courseid' AND parent = '0'", 'id', '*', '', 1)) {
|
||||
return reset($category);
|
||||
foreach ($contexts as $key => $context) {
|
||||
if (!$categoryrs = get_recordset_select("question_categories", "contextid = '{$context->id}'", 'sortorder, name', '*', '', 1)) {
|
||||
error('error getting category record');
|
||||
} else {
|
||||
if (!$category = rs_fetch_record($categoryrs)){
|
||||
// Otherwise, we need to make one
|
||||
$category = new stdClass;
|
||||
$contextname = print_context_name($context, false, true);
|
||||
$category->name = addslashes(get_string('defaultfor', 'question', $contextname));
|
||||
$category->info = addslashes(get_string('defaultinfofor', 'question', $contextname));
|
||||
$category->contextid = $context->id;
|
||||
$category->parent = 0;
|
||||
$category->sortorder = 999; // By default, all categories get this number, and are sorted alphabetically.
|
||||
$category->stamp = make_unique_id_code();
|
||||
if (!$category->id = insert_record('question_categories', $category)) {
|
||||
error('Error creating a default category for context '.print_context_name($context));
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($context->contextlevel == CONTEXT_COURSE){
|
||||
$toreturn = clone($category);
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, we need to make one
|
||||
$category = new stdClass;
|
||||
$category->name = get_string("default", "quiz");
|
||||
$category->info = get_string("defaultinfo", "quiz");
|
||||
$category->course = $courseid;
|
||||
$category->parent = 0;
|
||||
$category->sortorder = 999; // By default, all categories get this number, and are sorted alphabetically.
|
||||
$category->publish = 0;
|
||||
$category->stamp = make_unique_id_code();
|
||||
|
||||
if (!$category->id = insert_record("question_categories", $category)) {
|
||||
notify("Error creating a default category!");
|
||||
return false;
|
||||
}
|
||||
return $category;
|
||||
return $toreturn;
|
||||
}
|
||||
|
||||
function question_can_delete_cat($todelete){
|
||||
global $CFG;
|
||||
$record = get_record_sql("SELECT count(*) as count, c1.contextid as contextid FROM {$CFG->prefix}question_categories as c1,
|
||||
{$CFG->prefix}question_categories as c2 WHERE c2.id = $todelete
|
||||
AND c1.contextid = c2.contextid GROUP BY c1.contextid");
|
||||
$contextid = $record->contextid;
|
||||
$count = $record->count;
|
||||
if ($count < 2) {
|
||||
error('You can\'t delete that category it is the default category for this context.');
|
||||
} else {
|
||||
require_capability('moodle/question:managecategory', get_context_instance_by_id($contextid));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* prints a form to choose categories
|
||||
*/
|
||||
function question_category_form($course, $pageurl, $current, $recurse=1, $showhidden=false, $showquestiontext=false) {
|
||||
function question_category_form($contexts, $pageurl, $current, $recurse=1, $showhidden=false, $showquestiontext=false) {
|
||||
global $CFG;
|
||||
|
||||
/// Make sure the default category exists for this course
|
||||
get_default_question_category($course->id);
|
||||
|
||||
/// Get all the existing categories now
|
||||
$catmenu = question_category_options($course->id, true);
|
||||
$catmenu = question_category_options($contexts, false, 0, true);
|
||||
|
||||
$strcategory = get_string("category", "quiz");
|
||||
$strshow = get_string("show", "quiz");
|
||||
$streditcats = get_string("editcategories", "quiz");
|
||||
$strcategory = get_string('category', 'quiz');
|
||||
$strshow = get_string('show', 'quiz');
|
||||
$streditcats = get_string('editcategories', 'quiz');
|
||||
|
||||
popup_form ("edit.php?".$pageurl->get_query_string()."&category=", $catmenu, "catmenu", $current, "", "", "", false, "self", "<strong>$strcategory</strong>");
|
||||
popup_form ('edit.php?'.$pageurl->get_query_string().'&category=', $catmenu, 'catmenu', $current, '', '', '', false, 'self', "<strong>$strcategory</strong>");
|
||||
|
||||
echo '<form method="get" action="edit.php" id="displayoptions">';
|
||||
echo "<fieldset class='invisiblefieldset'>";
|
||||
|
@ -163,11 +178,15 @@ function question_category_form_checkbox($name, $checked) {
|
|||
* @param boolean $showhidden True if also hidden questions should be displayed
|
||||
* @param boolean $showquestiontext whether the text of each question should be shown in the list
|
||||
*/
|
||||
function question_list($course, $pageurl, $categoryid, $cm = null,
|
||||
function question_list($contexts, $pageurl, $categoryandcontext, $cm = null,
|
||||
$recurse=1, $page=0, $perpage=100, $showhidden=false, $sortorder='typename', $sortorderdecoded='qtype, name ASC',
|
||||
$showquestiontext = false) {
|
||||
$showquestiontext = false, $addcontexts = array()) {
|
||||
global $QTYPE_MENU, $USER, $CFG, $THEME, $COURSE;
|
||||
|
||||
list($categoryid, $contextid)= explode(',', $categoryandcontext);
|
||||
|
||||
$qtypemenu = $QTYPE_MENU;
|
||||
|
||||
global $QTYPE_MENU, $USER, $CFG, $THEME;
|
||||
|
||||
$strcategory = get_string("category", "quiz");
|
||||
$strquestion = get_string("question", "quiz");
|
||||
|
@ -182,6 +201,8 @@ function question_list($course, $pageurl, $categoryid, $cm = null,
|
|||
$strquestionname = get_string("questionname", "quiz");
|
||||
$strdelete = get_string("delete");
|
||||
$stredit = get_string("edit");
|
||||
$strmove = get_string('moveqtoanothercontext', 'question');
|
||||
$strview = get_string("view");
|
||||
$straction = get_string("action");
|
||||
$strrestore = get_string('restore');
|
||||
|
||||
|
@ -196,43 +217,54 @@ function question_list($course, $pageurl, $categoryid, $cm = null,
|
|||
return;
|
||||
}
|
||||
|
||||
if (!$category = get_record('question_categories', 'id', $categoryid)) {
|
||||
if (!$category = get_record('question_categories', 'id', $categoryid, 'contextid', $contextid)) {
|
||||
notify('Category not found!');
|
||||
return;
|
||||
}
|
||||
$canedit = has_capability('moodle/question:manage', get_context_instance(CONTEXT_COURSE, $category->course));
|
||||
$catcontext = get_context_instance_by_id($contextid);
|
||||
$canadd = has_capability('moodle/question:add', $catcontext);
|
||||
//check for capabilities on all questions in category, will also apply to sub cats.
|
||||
$caneditall =has_capability('moodle/question:editall', $catcontext);
|
||||
$canuseall =has_capability('moodle/question:useall', $catcontext);
|
||||
$canmoveall =has_capability('moodle/question:moveall', $catcontext);
|
||||
|
||||
if ($cm AND $cm->modname == 'quiz') {
|
||||
$quizid = $cm->instance;
|
||||
} else {
|
||||
$quizid = 0;
|
||||
}
|
||||
|
||||
$returnurl = $pageurl->out();
|
||||
$questionurl = new moodle_url("$CFG->wwwroot/question/question.php",
|
||||
array('returnurl' => $returnurl));
|
||||
if ($cm!==null){
|
||||
$questionurl->param('cmid', $cm->id);
|
||||
} else {
|
||||
$questionurl->param('courseid', $COURSE->id);
|
||||
}
|
||||
$questionmoveurl = new moodle_url("$CFG->wwwroot/question/contextmoveq.php",
|
||||
array('returnurl' => $returnurl));
|
||||
if ($cm!==null){
|
||||
$questionmoveurl->param('cmid', $cm->id);
|
||||
} else {
|
||||
$questionmoveurl->param('courseid', $COURSE->id);
|
||||
}
|
||||
echo '<div class="boxaligncenter">';
|
||||
$formatoptions = new stdClass;
|
||||
$formatoptions->noclean = true;
|
||||
echo format_text($category->info, FORMAT_MOODLE, $formatoptions, $course->id);
|
||||
echo format_text($category->info, FORMAT_MOODLE, $formatoptions, $COURSE->id);
|
||||
|
||||
echo '<table><tr>';
|
||||
|
||||
// check if editing questions in this category is allowed
|
||||
if ($canedit) {
|
||||
if ($canadd) {
|
||||
echo '<td valign="top" align="right">';
|
||||
$returnurl = urlencode($pageurl->out());
|
||||
$questionurl = new moodle_url("$CFG->wwwroot/question/question.php",
|
||||
array('returnurl' => $returnurl,
|
||||
'category' => $category->id));
|
||||
if ($cm!==null){
|
||||
$questionurl->param('cmid', $cm->id);
|
||||
}
|
||||
popup_form ($questionurl->out().'&qtype=', $QTYPE_MENU, "addquestion", "", "choose", "", "", false, "self", "<strong>$strcreatenewquestion</strong>");
|
||||
popup_form ($questionurl->out(false, array('category' => $category->id)).'&qtype=', $qtypemenu, "addquestion", "", "choose", "", "", false, "self", "<strong>$strcreatenewquestion</strong>");
|
||||
echo '</td><td valign="top" align="right">';
|
||||
helpbutton("questiontypes", $strcreatenewquestion, "quiz");
|
||||
echo '</td>';
|
||||
}
|
||||
else {
|
||||
echo '<td>';
|
||||
print_string("publishedit","quiz");
|
||||
print_string('nopermissionadd', 'question');
|
||||
echo '</td>';
|
||||
}
|
||||
|
||||
|
@ -265,6 +297,9 @@ function question_list($course, $pageurl, $categoryid, $cm = null,
|
|||
|
||||
print_paging_bar($totalnumber, $page, $perpage, $pageurl, 'qpage');
|
||||
|
||||
echo question_sort_options($pageurl, $sortorder);
|
||||
|
||||
|
||||
echo '<form method="post" action="edit.php">';
|
||||
echo '<fieldset class="invisiblefieldset" style="display: block;">';
|
||||
echo '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
|
||||
|
@ -272,12 +307,7 @@ function question_list($course, $pageurl, $categoryid, $cm = null,
|
|||
echo '<table id="categoryquestions" style="width: 100%"><tr>';
|
||||
echo "<th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">$straction</th>";
|
||||
|
||||
$sortoptions = array('alpha' => get_string("sortalpha", "quiz"),
|
||||
'typealpha' => get_string("sorttypealpha", "quiz"),
|
||||
'age' => get_string("sortage", "quiz"));
|
||||
$orderselect = choose_from_menu ($sortoptions, 'qsortorder', $sortorder, false, 'this.form.submit();', '0', true);
|
||||
$orderselect .= '<noscript><div><input type="submit" value="'.get_string("sortsubmit", "quiz").'" /></div></noscript>';
|
||||
echo "<th style=\"white-space:nowrap; text-align: left;\" class=\"header\" scope=\"col\">$strquestionname $orderselect</th>
|
||||
echo "<th style=\"white-space:nowrap; text-align: left;\" class=\"header\" scope=\"col\">$strquestionname</th>
|
||||
<th style=\"white-space:nowrap; text-align: right;\" class=\"header\" scope=\"col\">$strtype</th>";
|
||||
echo "</tr>\n";
|
||||
foreach ($questions as $question) {
|
||||
|
@ -299,22 +329,32 @@ function question_list($course, $pageurl, $categoryid, $cm = null,
|
|||
|
||||
echo "<tr>\n<td style=\"white-space:nowrap;\" $nameclass>\n";
|
||||
|
||||
$canuseq = question_has_capability_on($question, 'use', $question->category);
|
||||
if (function_exists('module_specific_actions')) {
|
||||
echo module_specific_actions($pageurl, $question->id, $cm->id);
|
||||
echo module_specific_actions($pageurl, $question->id, $cm->id, $canuseq);
|
||||
}
|
||||
|
||||
// preview
|
||||
link_to_popup_window('/question/preview.php?id=' . $question->id . '&quizid=' . $quizid, 'questionpreview',
|
||||
"<img src=\"$CFG->pixpath/t/preview.gif\" class=\"iconsmall\" alt=\"$strpreview\" />",
|
||||
0, 0, $strpreview, QUESTION_PREVIEW_POPUP_OPTIONS);
|
||||
|
||||
if ($canuseq) {
|
||||
link_to_popup_window('/question/preview.php?id=' . $question->id . '&quizid=' . $quizid, 'questionpreview',
|
||||
"<img src=\"$CFG->pixpath/t/preview.gif\" class=\"iconsmall\" alt=\"$strpreview\" />",
|
||||
0, 0, $strpreview, QUESTION_PREVIEW_POPUP_OPTIONS);
|
||||
}
|
||||
// edit, hide, delete question, using question capabilities, not quiz capabilieies
|
||||
if ($canedit) {
|
||||
$questionparams = (($cm !== null)? array('cmid' => $cm->id) : array()) +
|
||||
(array('returnurl' => $pageurl->out(), 'id'=>$question->id));
|
||||
$questionurl = new moodle_url("$CFG->wwwroot/question/question.php", $questionparams);
|
||||
echo "<a title=\"$stredit\" href=\"".$questionurl->out()."\"><img
|
||||
if (question_has_capability_on($question, 'edit', $question->category) || question_has_capability_on($question, 'move', $question->category)) {
|
||||
echo "<a title=\"$stredit\" href=\"".$questionurl->out(false, array('id'=>$question->id))."\"><img
|
||||
src=\"$CFG->pixpath/t/edit.gif\" alt=\"$stredit\" /></a> ";
|
||||
} elseif (question_has_capability_on($question, 'view', $question->category)){
|
||||
echo "<a title=\"$strview\" href=\"".$questionurl->out(false, array('id'=>$question->id))."\"><img
|
||||
src=\"$CFG->pixpath/i/info.gif\" alt=\"$strview\" /></a> ";
|
||||
}
|
||||
|
||||
if (question_has_capability_on($question, 'move', $question->category) && question_has_capability_on($question, 'view', $question->category)) {
|
||||
echo "<a title=\"$strmove\" href=\"".$questionurl->out(false, array('id'=>$question->id, 'movecontext'=>1))."\"><img
|
||||
src=\"$CFG->pixpath/t/move.gif\" alt=\"$strmove\" /></a> ";
|
||||
}
|
||||
|
||||
if (question_has_capability_on($question, 'edit', $question->category)) {
|
||||
// hide-feature
|
||||
if($question->hidden) {
|
||||
echo "<a title=\"$strrestore\" href=\"edit.php?".$pageurl->get_query_string()."&unhide=$question->id&sesskey=$USER->sesskey\"><img
|
||||
|
@ -324,7 +364,9 @@ function question_list($course, $pageurl, $categoryid, $cm = null,
|
|||
src=\"$CFG->pixpath/t/delete.gif\" alt=\"$strdelete\" /></a>";
|
||||
}
|
||||
}
|
||||
echo " <input title=\"$strselect\" type=\"checkbox\" name=\"q$question->id\" value=\"1\" />";
|
||||
if ($caneditall || $canmoveall || $canuseall){
|
||||
echo " <input title=\"$strselect\" type=\"checkbox\" name=\"q$question->id\" value=\"1\" />";
|
||||
}
|
||||
echo "</td>\n";
|
||||
|
||||
echo "<td $nameclass>" . format_string($question->name) . "</td>\n";
|
||||
|
@ -338,14 +380,13 @@ function question_list($course, $pageurl, $categoryid, $cm = null,
|
|||
$formatoptions->noclean = true;
|
||||
$formatoptions->para = false;
|
||||
echo format_text($question->questiontext, $question->questiontextformat,
|
||||
$formatoptions, $course->id);
|
||||
$formatoptions, $COURSE->id);
|
||||
echo "</td></tr>\n";
|
||||
}
|
||||
}
|
||||
echo "</table>\n";
|
||||
|
||||
$paging = print_paging_bar($totalnumber, $page, $perpage, $pageurl, 'qpage',
|
||||
false, true);
|
||||
$paging = print_paging_bar($totalnumber, $page, $perpage, $pageurl, 'qpage', false, true);
|
||||
if ($totalnumber > DEFAULT_QUESTIONS_PER_PAGE) {
|
||||
if ($perpage == DEFAULT_QUESTIONS_PER_PAGE) {
|
||||
$showall = '<a href="edit.php?'.$pageurl->get_query_string(array('qperpage'=>1000)).'">'.get_string('showall', 'moodle', $totalnumber).'</a>';
|
||||
|
@ -361,28 +402,146 @@ function question_list($course, $pageurl, $categoryid, $cm = null,
|
|||
}
|
||||
echo $paging;
|
||||
|
||||
echo '<table class="quiz-edit-selected"><tr><td colspan="2">';
|
||||
echo '<a href="javascript:select_all_in(\'TABLE\', null, \'categoryquestions\');">'.$strselectall.'</a> /'.
|
||||
' <a href="javascript:deselect_all_in(\'TABLE\', null, \'categoryquestions\');">'.$strselectnone.'</a>'.
|
||||
'</td><td align="right"><b> '.get_string('withselected', 'quiz').':</b></td></tr><tr><td>';
|
||||
if ($caneditall || $canmoveall || $canuseall){
|
||||
echo '<a href="javascript:select_all_in(\'TABLE\', null, \'categoryquestions\');">'.$strselectall.'</a> /'.
|
||||
' <a href="javascript:deselect_all_in(\'TABLE\', null, \'categoryquestions\');">'.$strselectnone.'</a>';
|
||||
echo '<br />';
|
||||
echo '<strong> '.get_string('withselected', 'quiz').':</strong><br />';
|
||||
|
||||
if (function_exists('module_specific_buttons')) {
|
||||
echo module_specific_buttons($cm->id);
|
||||
}
|
||||
// print delete and move selected question
|
||||
if ($canedit) {
|
||||
echo '<input type="submit" name="deleteselected" value="'.$strdelete."\" /></td><td>\n";
|
||||
echo '<input type="submit" name="move" value="'.get_string('moveto', 'quiz')."\" />\n";
|
||||
question_category_select_menu($course->id, false, true, $category->id);
|
||||
}
|
||||
echo "</td></tr></table>";
|
||||
if (function_exists('module_specific_buttons')) {
|
||||
echo module_specific_buttons($cm->id);
|
||||
}
|
||||
// print delete and move selected question
|
||||
if ($caneditall) {
|
||||
echo '<input type="submit" name="deleteselected" value="'.$strdelete."\" />\n";
|
||||
}
|
||||
if ($canmoveall && count($addcontexts)) {
|
||||
echo '<input type="submit" name="move" value="'.get_string('moveto', 'quiz')."\" />\n";
|
||||
question_category_select_menu($addcontexts, false, 0, "$category->id,$category->contextid");
|
||||
}
|
||||
|
||||
if (function_exists('module_specific_controls')) {
|
||||
echo module_specific_controls($totalnumber, $recurse, $category->id, $cm->id);
|
||||
if (function_exists('module_specific_controls') && $canuseall) {
|
||||
echo module_specific_controls($totalnumber, $recurse, $category, $cm->id);
|
||||
}
|
||||
}
|
||||
echo '</fieldset>';
|
||||
echo "</form>\n";
|
||||
}
|
||||
function question_sort_options($pageurl, $sortorder){
|
||||
global $USER;
|
||||
//sort options
|
||||
$html = "<div class=\"mdl-align\">";
|
||||
$html .= '<form method="post" action="edit.php">';
|
||||
$html .= '<fieldset class="invisiblefieldset" style="display: block;">';
|
||||
$html .= '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
|
||||
$html .= $pageurl->hidden_params_out(array('qsortorder'));
|
||||
$sortoptions = array('alpha' => get_string("sortalpha", "quiz"),
|
||||
'typealpha' => get_string("sorttypealpha", "quiz"),
|
||||
'age' => get_string("sortage", "quiz"));
|
||||
$html .= choose_from_menu ($sortoptions, 'qsortorder', $sortorder, false, 'this.form.submit();', '0', true);
|
||||
$html .= '<noscript><div><input type="submit" value="'.get_string("sortsubmit", "quiz").'" /></div></noscript>';
|
||||
$html .= '</fieldset>';
|
||||
$html .= "</form>\n";
|
||||
$html .= "</div>\n";
|
||||
return $html;
|
||||
}
|
||||
|
||||
function question_showbank_actions($pageurl, $cm){
|
||||
global $CFG;
|
||||
/// Now, check for commands on this page and modify variables as necessary
|
||||
if (isset($_REQUEST['move']) and confirm_sesskey()) { /// Move selected questions to new category
|
||||
$category = required_param('category', PARAM_SEQUENCE);
|
||||
list($tocategoryid, $contextid) = explode(',', $category);
|
||||
if (! $tocategory = get_record('question_categories', 'id', $tocategoryid, 'contextid', $contextid)) {
|
||||
error('Could not find category record');
|
||||
}
|
||||
$tocontext = get_context_instance_by_id($contextid);
|
||||
require_capability('moodle/question:add', $tocontext);
|
||||
$questionids = array();
|
||||
foreach ($_POST as $key => $value) { // Parse input for question ids
|
||||
if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
|
||||
$key = $matches[1];
|
||||
$questionids[] = $key;
|
||||
}
|
||||
}
|
||||
if ($questionids){
|
||||
$questionidlist = join($questionids, ',');
|
||||
$sql = "SELECT q.*, c.contextid FROM {$CFG->prefix}question q, {$CFG->prefix}question_categories c WHERE q.id IN ($questionidlist) AND c.id = q.category";
|
||||
if (!$questions = get_records_sql($sql)){
|
||||
print_error('questiondoesnotexist', 'question', $pageurl->out());
|
||||
}
|
||||
$checkforfiles = false;
|
||||
foreach ($questions as $question){
|
||||
//check capabilities
|
||||
question_require_capability_on($question, 'move');
|
||||
$fromcontext = get_context_instance_by_id($question->contextid);
|
||||
if (get_filesdir_from_context($fromcontext) != get_filesdir_from_context($tocontext)){
|
||||
$checkforfiles = true;
|
||||
}
|
||||
}
|
||||
$returnurl = $pageurl->out(false, array('category'=>"$tocategoryid,$contextid"));
|
||||
if (!$checkforfiles){
|
||||
foreach ($questionids as $questionid){
|
||||
//move question
|
||||
if (!set_field('question', 'category', $tocategory->id, 'id', $questionid)) {
|
||||
error('Could not update category field');
|
||||
}
|
||||
}
|
||||
redirect($returnurl);
|
||||
} else {
|
||||
$movecontexturl = new moodle_url($CFG->wwwroot.'/question/contextmoveq.php',
|
||||
array('returnurl' => $returnurl,
|
||||
'ids'=>$questionidlist,
|
||||
'tocatid'=> $tocategoryid));
|
||||
if ($cm){
|
||||
$movecontexturl->param('cmid', $cm->id);
|
||||
} else {
|
||||
$movecontexturl->param('courseid', $COURSE->id);
|
||||
}
|
||||
redirect($movecontexturl->out());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['deleteselected'])) { // delete selected questions from the category
|
||||
|
||||
if (isset($_REQUEST['confirm']) and confirm_sesskey()) { // teacher has already confirmed the action
|
||||
$deleteselected = required_param('deleteselected');
|
||||
if ($_REQUEST['confirm'] == md5($deleteselected)) {
|
||||
if ($questionlist = explode(',', $deleteselected)) {
|
||||
// for each question either hide it if it is in use or delete it
|
||||
foreach ($questionlist as $questionid) {
|
||||
question_require_capability_on($questionid, 'edit');
|
||||
if (record_exists('quiz_question_instances', 'question', $questionid) or
|
||||
record_exists('question_states', 'originalquestion', $questionid)) {
|
||||
if (!set_field('question', 'hidden', 1, 'id', $questionid)) {
|
||||
question_require_capability_on($questionid, 'edit');
|
||||
error('Was not able to hide question');
|
||||
}
|
||||
} else {
|
||||
delete_question($questionid);
|
||||
}
|
||||
}
|
||||
}
|
||||
redirect($pageurl->out());
|
||||
} else {
|
||||
error("Confirmation string was incorrect");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Unhide a question
|
||||
if(isset($_REQUEST['unhide']) && confirm_sesskey()) {
|
||||
$unhide = required_param('unhide', PARAM_INT);
|
||||
question_require_capability_on($unhide, 'edit');
|
||||
if(!set_field('question', 'hidden', 0, 'id', $unhide)) {
|
||||
error("Failed to unhide the question.");
|
||||
}
|
||||
redirect($pageurl->out());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Shows the question bank editing interface.
|
||||
*
|
||||
|
@ -400,123 +559,70 @@ function question_list($course, $pageurl, $categoryid, $cm = null,
|
|||
* {@link http://maths.york.ac.uk/serving_maths}
|
||||
* @param moodle_url $pageurl object representing this pages url.
|
||||
*/
|
||||
function question_showbank($pageurl, $cm, $page, $perpage, $sortorder, $sortorderdecoded, $cat, $recurse, $showhidden, $showquestiontext){
|
||||
global $COURSE, $USER;
|
||||
function question_showbank($tabname, $contexts, $pageurl, $cm, $page, $perpage, $sortorder, $sortorderdecoded, $cat, $recurse, $showhidden, $showquestiontext){
|
||||
global $COURSE;
|
||||
|
||||
/// Now, check for commands on this page and modify variables as necessary
|
||||
if (isset($_REQUEST['move']) and confirm_sesskey()) { /// Move selected questions to new category
|
||||
$tocategoryid = required_param('category', PARAM_INT);
|
||||
if (!$tocategory = get_record('question_categories', 'id', $tocategoryid)) {
|
||||
error('Invalid category');
|
||||
}
|
||||
if (!has_capability('moodle/question:managecategory', get_context_instance(CONTEXT_COURSE, $tocategory->course))){
|
||||
error(get_string('categorynoedit', 'quiz', $tocategory->name), $pageurl->out());
|
||||
}
|
||||
foreach ($_POST as $key => $value) { // Parse input for question ids
|
||||
if (isset($_REQUEST['deleteselected'])){ // teacher still has to confirm
|
||||
// make a list of all the questions that are selected
|
||||
$rawquestions = $_REQUEST;
|
||||
$questionlist = ''; // comma separated list of ids of questions to be deleted
|
||||
$questionnames = ''; // string with names of questions separated by <br /> with
|
||||
// an asterix in front of those that are in use
|
||||
$inuse = false; // set to true if at least one of the questions is in use
|
||||
foreach ($rawquestions as $key => $value) { // Parse input for question ids
|
||||
if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
|
||||
$key = $matches[1];
|
||||
if (!set_field('question', 'category', $tocategory->id, 'id', $key)) {
|
||||
error('Could not update category field');
|
||||
$key = $matches[1]; $questionlist .= $key.',';
|
||||
question_require_capability_on($key, 'edit');
|
||||
if (record_exists('quiz_question_instances', 'question', $key) or
|
||||
record_exists('question_states', 'originalquestion', $key)) {
|
||||
$questionnames .= '* ';
|
||||
$inuse = true;
|
||||
}
|
||||
$questionnames .= get_field('question', 'name', 'id', $key).'<br />';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['deleteselected'])) { // delete selected questions from the category
|
||||
|
||||
if (isset($_REQUEST['confirm']) and confirm_sesskey()) { // teacher has already confirmed the action
|
||||
$deleteselected = required_param('deleteselected');
|
||||
if ($_REQUEST['confirm'] == md5($deleteselected)) {
|
||||
if ($questionlist = explode(',', $deleteselected)) {
|
||||
// for each question either hide it if it is in use or delete it
|
||||
foreach ($questionlist as $questionid) {
|
||||
if (record_exists('quiz_question_instances', 'question', $questionid) or
|
||||
record_exists('question_states', 'originalquestion', $questionid)) {
|
||||
if (!set_field('question', 'hidden', 1, 'id', $questionid)) {
|
||||
error('Was not able to hide question');
|
||||
}
|
||||
} else {
|
||||
delete_question($questionid);
|
||||
}
|
||||
}
|
||||
}
|
||||
echo '</td></tr>';
|
||||
echo '</table>';
|
||||
echo '</div>';
|
||||
redirect($pageurl->out());
|
||||
} else {
|
||||
error("Confirmation string was incorrect");
|
||||
}
|
||||
|
||||
} else { // teacher still has to confirm
|
||||
// make a list of all the questions that are selected
|
||||
$rawquestions = $_REQUEST;
|
||||
$questionlist = ''; // comma separated list of ids of questions to be deleted
|
||||
$questionnames = ''; // string with names of questions separated by <br /> with
|
||||
// an asterix in front of those that are in use
|
||||
$inuse = false; // set to true if at least one of the questions is in use
|
||||
foreach ($rawquestions as $key => $value) { // Parse input for question ids
|
||||
if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
|
||||
$key = $matches[1]; $questionlist .= $key.',';
|
||||
if (record_exists('quiz_question_instances', 'question', $key) or
|
||||
record_exists('question_states', 'originalquestion', $key)) {
|
||||
$questionnames .= '* ';
|
||||
$inuse = true;
|
||||
}
|
||||
$questionnames .= get_field('question', 'name', 'id', $key).'<br />';
|
||||
}
|
||||
}
|
||||
if (!$questionlist) { // no questions were selected
|
||||
redirect($pageurl->out());
|
||||
}
|
||||
$questionlist = rtrim($questionlist, ',');
|
||||
|
||||
// Add an explanation about questions in use
|
||||
if ($inuse) {
|
||||
$questionnames .= '<br />'.get_string('questionsinuse', 'quiz');
|
||||
}
|
||||
notice_yesno(get_string("deletequestionscheck", "quiz", $questionnames),
|
||||
$pageurl->out(), $pageurl->out(),
|
||||
array('sesskey' => $USER->sesskey, 'deleteselected' => $questionlist, 'confirm' => md5($questionlist)),
|
||||
NULL, 'post', 'get');
|
||||
|
||||
echo '</td></tr>';
|
||||
echo '</table>';
|
||||
print_footer($COURSE);
|
||||
exit;
|
||||
if (!$questionlist) { // no questions were selected
|
||||
redirect($pageurl->out());
|
||||
}
|
||||
$questionlist = rtrim($questionlist, ',');
|
||||
|
||||
// Add an explanation about questions in use
|
||||
if ($inuse) {
|
||||
$questionnames .= '<br />'.get_string('questionsinuse', 'quiz');
|
||||
}
|
||||
notice_yesno(get_string("deletequestionscheck", "quiz", $questionnames),
|
||||
$pageurl->out_action(array('deleteselected'=>$questionlist, 'confirm'=>md5($questionlist))),
|
||||
$pageurl->out_action());
|
||||
|
||||
echo '</td></tr>';
|
||||
echo '</table>';
|
||||
print_footer($COURSE);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Unhide a question
|
||||
if(isset($_REQUEST['unhide']) && confirm_sesskey()) {
|
||||
$unhide = required_param('unhide', PARAM_INT);
|
||||
if(!set_field('question', 'hidden', 0, 'id', $unhide)) {
|
||||
error("Failed to unhide the question.");
|
||||
}
|
||||
redirect($pageurl->out());
|
||||
}
|
||||
|
||||
// starts with category selection form
|
||||
print_box_start('generalbox questionbank');
|
||||
print_heading(get_string('questionbank', 'question'), '', 2);
|
||||
question_category_form($COURSE, $pageurl, $cat, $recurse,
|
||||
$showhidden, $showquestiontext);
|
||||
question_category_form($contexts->having_one_edit_tab_cap($tabname), $pageurl, $cat, $recurse, $showhidden, $showquestiontext);
|
||||
|
||||
// continues with list of questions
|
||||
question_list($COURSE, $pageurl, $cat, isset($cm) ? $cm : null,
|
||||
$recurse, $page, $perpage, $showhidden, $sortorder, $sortorderdecoded,
|
||||
$showquestiontext);
|
||||
question_list($contexts->having_one_edit_tab_cap($tabname), $pageurl, $cat, isset($cm) ? $cm : null,
|
||||
$recurse, $page, $perpage, $showhidden, $sortorder, $sortorderdecoded, $showquestiontext,
|
||||
$contexts->having_cap('moodle/question:add'));
|
||||
|
||||
print_box_end();
|
||||
}
|
||||
/**
|
||||
* Common setup for all pages for editing questions.
|
||||
* @param string $edittab code for this edit tab
|
||||
* @param boolean $requirecmid require cmid? default false
|
||||
* @param boolean $requirecourseid require courseid, if cmid is not given? default true
|
||||
* @return array $thispageurl, $courseid, $cmid, $cm, $module, $pagevars
|
||||
* @return array $thispageurl, $contexts, $cmid, $cm, $module, $pagevars
|
||||
*/
|
||||
function question_edit_setup($requirecmid = false, $requirecourseid = true){
|
||||
global $COURSE;
|
||||
function question_edit_setup($edittab, $requirecmid = false, $requirecourseid = true){
|
||||
global $COURSE, $QUESTION_EDITTABCAPS;
|
||||
|
||||
//$thispageurl is used to construct urls for all question edit pages we link to from this page. It contains an array
|
||||
//of parameters that are passed from page to page.
|
||||
$thispageurl = new moodle_url();
|
||||
|
@ -529,6 +635,8 @@ function question_edit_setup($requirecmid = false, $requirecourseid = true){
|
|||
list($module, $cm) = get_module_from_cmid($cmid);
|
||||
$courseid = $cm->course;
|
||||
$thispageurl->params(compact('cmid'));
|
||||
require_login($courseid, false, $cm);
|
||||
$thiscontext = get_context_instance(CONTEXT_MODULE, $cmid);
|
||||
} else {
|
||||
$module = null;
|
||||
$cm = null;
|
||||
|
@ -539,9 +647,21 @@ function question_edit_setup($requirecmid = false, $requirecourseid = true){
|
|||
}
|
||||
if ($courseid){
|
||||
$thispageurl->params(compact('courseid'));
|
||||
require_login($courseid, false);
|
||||
$thiscontext = get_context_instance(CONTEXT_COURSE, $courseid);
|
||||
} else {
|
||||
$thiscontext = null;
|
||||
}
|
||||
}
|
||||
require_login($courseid, false);
|
||||
|
||||
if ($thiscontext){
|
||||
$contexts = new question_edit_contexts($thiscontext);
|
||||
$contexts->require_one_edit_tab_cap($edittab);
|
||||
|
||||
} else {
|
||||
$contexts = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
$pagevars['qpage'] = optional_param('qpage', -1, PARAM_INT);
|
||||
|
@ -549,8 +669,8 @@ function question_edit_setup($requirecmid = false, $requirecourseid = true){
|
|||
//pass 'cat' from page to page and when 'category' comes from a drop down menu
|
||||
//then we also reset the qpage so we go to page 1 of
|
||||
//a new cat.
|
||||
$pagevars['cat'] = optional_param('cat', 0, PARAM_INT);
|
||||
if ($category = optional_param('category', 0, PARAM_INT)){
|
||||
$pagevars['cat'] = optional_param('cat', 0, PARAM_SEQUENCE);// if empty will be set up later
|
||||
if ($category = optional_param('category', 0, PARAM_SEQUENCE)){
|
||||
$pagevars['cat'] = $category;
|
||||
$pagevars['qpage'] = 0;
|
||||
}
|
||||
|
@ -583,11 +703,21 @@ function question_edit_setup($requirecmid = false, $requirecourseid = true){
|
|||
$pagevars['qsortorder'] = 'typealpha';
|
||||
}
|
||||
|
||||
$defaultcategory = question_make_default_categories($contexts->all());
|
||||
|
||||
if (empty($pagevars['cat']) or !count_records_select("question_categories", "id = '".$pagevars['cat']."' AND (course = '{$COURSE->id}' OR publish = '1')")) {
|
||||
$category = get_default_question_category($COURSE->id);
|
||||
$pagevars['cat'] = $category->id;
|
||||
$thispageurl->param('cat', $category->id);
|
||||
$contextlistarr = array();
|
||||
foreach ($contexts->having_one_edit_tab_cap($edittab) as $context){
|
||||
$contextlistarr[] = "'$context->id'";
|
||||
}
|
||||
$contextlist = join($contextlistarr, ' ,');
|
||||
if (!empty($pagevars['cat'])){
|
||||
$catparts = explode(',', $pagevars['cat']);
|
||||
if (!$catparts[0] || (FALSE !== array_search($catparts[1], $contextlistarr)) || !count_records_select("question_categories", "id = '".$catparts[0]."' AND contextid = $catparts[1]")) {
|
||||
error(get_string('invalidcategory', 'quiz'));
|
||||
}
|
||||
} else {
|
||||
$category = $defaultcategory;
|
||||
$pagevars['cat'] = "$category->id,$category->contextid";
|
||||
}
|
||||
|
||||
if(($recurse = optional_param('recurse', -1, PARAM_BOOL)) != -1) {
|
||||
|
@ -618,6 +748,191 @@ function question_edit_setup($requirecmid = false, $requirecourseid = true){
|
|||
}
|
||||
|
||||
|
||||
return array($thispageurl, $courseid, $cmid, $cm, $module, $pagevars);
|
||||
return array($thispageurl, $contexts, $cmid, $cm, $module, $pagevars);
|
||||
}
|
||||
class question_edit_contexts{
|
||||
var $allcontexts;
|
||||
/**
|
||||
* @param current context
|
||||
*/
|
||||
function question_edit_contexts($thiscontext){
|
||||
$pcontextids = get_parent_contexts($thiscontext);
|
||||
$contexts = array($thiscontext);
|
||||
foreach ($pcontextids as $pcontextid){
|
||||
$contexts[] = get_context_instance_by_id($pcontextid);
|
||||
}
|
||||
$this->allcontexts = $contexts;
|
||||
}
|
||||
/**
|
||||
* @return array all parent contexts
|
||||
*/
|
||||
function all(){
|
||||
return $this->allcontexts;
|
||||
}
|
||||
/**
|
||||
* @return object lowest context which must be either the module or course context
|
||||
*/
|
||||
function lowest(){
|
||||
return $this->allcontexts[0];
|
||||
}
|
||||
/**
|
||||
* @param string $cap capability
|
||||
* @return array parent contexts having capability, zero based index
|
||||
*/
|
||||
function having_cap($cap){
|
||||
$contextswithcap = array();
|
||||
foreach ($this->allcontexts as $context){
|
||||
if (has_capability($cap, $context)){
|
||||
$contextswithcap[] = $context;
|
||||
}
|
||||
}
|
||||
return $contextswithcap;
|
||||
}
|
||||
/**
|
||||
* @param array $caps capabilities
|
||||
* @return array parent contexts having at least one of $caps, zero based index
|
||||
*/
|
||||
function having_one_cap($caps){
|
||||
$contextswithacap = array();
|
||||
foreach ($this->allcontexts as $context){
|
||||
foreach ($caps as $cap){
|
||||
if (has_capability($cap, $context)){
|
||||
$contextswithacap[] = $context;
|
||||
break; //done with caps loop
|
||||
}
|
||||
}
|
||||
}
|
||||
return $contextswithacap;
|
||||
}
|
||||
/**
|
||||
* @param string $tabname edit tab name
|
||||
* @return array parent contexts having at least one of $caps, zero based index
|
||||
*/
|
||||
function having_one_edit_tab_cap($tabname){
|
||||
global $QUESTION_EDITTABCAPS;
|
||||
return $this->having_one_cap($QUESTION_EDITTABCAPS[$tabname]);
|
||||
}
|
||||
/**
|
||||
* Has at least one parent context got the cap $cap?
|
||||
*
|
||||
* @param string $cap capability
|
||||
* @return boolean
|
||||
*/
|
||||
function have_cap($cap){
|
||||
return (count($this->having_cap($cap)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Has at least one parent context got one of the caps $caps?
|
||||
*
|
||||
* @param string $cap capability
|
||||
* @return boolean
|
||||
*/
|
||||
function have_one_cap($caps){
|
||||
foreach ($caps as $cap){
|
||||
if ($this->have_cap($cap)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Has at least one parent context got one of the caps for actions on $tabname
|
||||
*
|
||||
* @param string $tabname edit tab name
|
||||
* @return boolean
|
||||
*/
|
||||
function have_one_edit_tab_cap($tabname){
|
||||
global $QUESTION_EDITTABCAPS;
|
||||
return $this->have_one_cap($QUESTION_EDITTABCAPS[$tabname]);
|
||||
}
|
||||
/**
|
||||
* Throw error if at least one parent context hasn't got the cap $cap
|
||||
*
|
||||
* @param string $cap capability
|
||||
*/
|
||||
function require_cap($cap){
|
||||
if (!$this->have_cap($cap)){
|
||||
print_error('nopermissions', '', '', $cap);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Throw error if at least one parent context hasn't got one of the caps $caps
|
||||
*
|
||||
* @param array $cap capabilities
|
||||
*/
|
||||
function require_one_cap($caps){
|
||||
if (!$this->have_one_cap($caps)){
|
||||
$capsstring = join($caps, ', ');
|
||||
print_error('nopermissions', '', '', $capsstring);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Throw error if at least one parent context hasn't got one of the caps $caps
|
||||
*
|
||||
* @param string $tabname edit tab name
|
||||
*/
|
||||
function require_one_edit_tab_cap($tabname){
|
||||
if (!$this->have_one_edit_tab_cap($tabname)){
|
||||
print_error('nopermissions', '', '', 'access question edit tab '.$tabname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//capabilities for each page of edit tab.
|
||||
//this determines which contexts' categories are available. At least one
|
||||
//page is displayed if user has one of the capability on at least one context
|
||||
$QUESTION_EDITTABCAPS = array(
|
||||
'editq' => array('moodle/question:add',
|
||||
'moodle/question:editmine',
|
||||
'moodle/question:editall',
|
||||
'moodle/question:viewmine',
|
||||
'moodle/question:viewall',
|
||||
'moodle/question:usemine',
|
||||
'moodle/question:useall',
|
||||
'moodle/question:movemine',
|
||||
'moodle/question:moveall'),
|
||||
'questions'=>array('moodle/question:add',
|
||||
'moodle/question:editmine',
|
||||
'moodle/question:editall',
|
||||
'moodle/question:viewmine',
|
||||
'moodle/question:viewall',
|
||||
'moodle/question:movemine',
|
||||
'moodle/question:moveall'),
|
||||
'categories'=>array('moodle/question:managecategory'),
|
||||
'import'=>array('moodle/question:add'),
|
||||
'export'=>array('moodle/question:viewall', 'moodle/question:viewmine'));
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Make sure user is logged in as required in this context.
|
||||
*/
|
||||
function require_login_in_context($contextorid = null){
|
||||
if (!is_object($contextorid)){
|
||||
$context = get_context_instance_by_id($contextorid);
|
||||
} else {
|
||||
$context = $contextorid;
|
||||
}
|
||||
if ($context && ($context->contextlevel == CONTEXT_COURSE)) {
|
||||
require_login($context->instanceid);
|
||||
} else if ($context && ($context->contextlevel == CONTEXT_MODULE)) {
|
||||
if ($cm = get_record('course_modules','id',$context->instanceid)) {
|
||||
if (!$course = get_record('course', 'id', $cm->course)) {
|
||||
error('Incorrect course.');
|
||||
}
|
||||
require_course_login($course, true, $cm);
|
||||
|
||||
} else {
|
||||
error('Incorrect course module id.');
|
||||
}
|
||||
} else if ($context && ($context->contextlevel == CONTEXT_SYSTEM)) {
|
||||
if (!empty($CFG->forcelogin)) {
|
||||
require_login();
|
||||
}
|
||||
|
||||
} else {
|
||||
require_login();
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -10,66 +10,44 @@
|
|||
*/
|
||||
|
||||
require_once("../config.php");
|
||||
require_once( "editlib.php" );
|
||||
require_once("editlib.php");
|
||||
require_once("export_form.php");
|
||||
|
||||
list($thispageurl, $courseid, $cmid, $cm, $module, $pagevars) = question_edit_setup();
|
||||
list($thispageurl, $contexts, $cmid, $cm, $module, $pagevars) = question_edit_setup('export');
|
||||
|
||||
$cattofile = optional_param('cattofile',0, PARAM_BOOL);
|
||||
|
||||
$exportfilename = optional_param('exportfilename','',PARAM_FILE );
|
||||
$format = optional_param('format','', PARAM_FILE );
|
||||
$categoryid = optional_param('category',0,PARAM_INT);
|
||||
|
||||
// get display strings
|
||||
$txt = new object;
|
||||
$txt->category = get_string('category','quiz');
|
||||
$txt->download = get_string('download','quiz');
|
||||
$txt->downloadextra = get_string('downloadextra','quiz');
|
||||
$txt->exporterror = get_string('exporterror','quiz');
|
||||
$txt->exportname = get_string('exportname','quiz');
|
||||
$txt->category = get_string('category', 'quiz');
|
||||
$txt->download = get_string('download', 'quiz');
|
||||
$txt->downloadextra = get_string('downloadextra', 'quiz');
|
||||
$txt->exporterror = get_string('exporterror', 'quiz');
|
||||
$txt->exportname = get_string('exportname', 'quiz');
|
||||
$txt->exportquestions = get_string('exportquestions', 'quiz');
|
||||
$txt->fileformat = get_string('fileformat','quiz');
|
||||
$txt->exportcategory = get_string('exportcategory','quiz');
|
||||
$txt->modulename = get_string('modulename','quiz');
|
||||
$txt->modulenameplural = get_string('modulenameplural','quiz');
|
||||
$txt->tofile = get_string('tofile','quiz');
|
||||
$txt->fileformat = get_string('fileformat', 'quiz');
|
||||
$txt->exportcategory = get_string('exportcategory', 'quiz');
|
||||
$txt->modulename = get_string('modulename', 'quiz');
|
||||
$txt->modulenameplural = get_string('modulenameplural', 'quiz');
|
||||
$txt->tofile = get_string('tofile', 'quiz');
|
||||
|
||||
|
||||
if (!$course = get_record("course", "id", $courseid)) {
|
||||
error("Course does not exist!");
|
||||
}
|
||||
|
||||
// make sure we are using the user's most recent category choice
|
||||
if (empty($categoryid)) {
|
||||
$categoryid = $pagevars['cat'];
|
||||
}
|
||||
|
||||
if (!$category = get_record("question_categories", "id", $categoryid)) {
|
||||
$category = get_default_question_category($courseid);
|
||||
}
|
||||
|
||||
if (!$categorycourse = get_record("course", "id", $category->course)) {
|
||||
print_error('nocategory','quiz');
|
||||
}
|
||||
|
||||
|
||||
// check role capability
|
||||
$context = get_context_instance(CONTEXT_COURSE, $course->id);
|
||||
require_capability('moodle/question:export', $context);
|
||||
|
||||
// ensure the files area exists for this course
|
||||
make_upload_directory( "$course->id" );
|
||||
|
||||
// check category is valid
|
||||
$validcats = question_category_options( $course->id, true, false );
|
||||
if (!array_key_exists( $categoryid, $validcats)) {
|
||||
print_error( 'invalidcategory','quiz' );
|
||||
make_upload_directory("$COURSE->id");
|
||||
list($catid, $catcontext) = explode(',', $pagevars['cat']);
|
||||
if (!$category = get_record("question_categories", "id", $catid, 'contextid', $catcontext)) {
|
||||
print_error('nocategory','quiz');
|
||||
}
|
||||
|
||||
/// Header
|
||||
if ($cm!==null) {
|
||||
$strupdatemodule = has_capability('moodle/course:manageactivities', get_context_instance(CONTEXT_COURSE, $course->id))
|
||||
? update_module_button($cm->id, $course->id, get_string('modulename', $cm->modname))
|
||||
$strupdatemodule = has_capability('moodle/course:manageactivities', $contexts->lowest())
|
||||
? update_module_button($cm->id, $COURSE->id, get_string('modulename', $cm->modname))
|
||||
: "";
|
||||
$navlinks = array();
|
||||
$navlinks[] = array('name' => get_string('modulenameplural', $cm->modname), 'link' => "$CFG->wwwroot/mod/{$cm->modname}/index.php?id=$course->id", 'type' => 'activity');
|
||||
|
@ -94,112 +72,73 @@
|
|||
include('tabs.php');
|
||||
}
|
||||
|
||||
if (!empty($format)) { /// Filename
|
||||
$exportfilename = default_export_filename($COURSE, $category);
|
||||
$export_form = new question_export_form($thispageurl, array('contexts'=>$contexts->having_one_edit_tab_cap('export'), 'defaultcategory'=>$pagevars['cat'],
|
||||
'defaultfilename'=>$exportfilename));
|
||||
|
||||
if (!confirm_sesskey()) {
|
||||
print_error( 'sesskey' );
|
||||
|
||||
if ($from_form = $export_form->get_data()) { /// Filename
|
||||
|
||||
|
||||
if (! is_readable("format/$from_form->format/format.php")) {
|
||||
error("Format not known ($from_form->format)");
|
||||
}
|
||||
|
||||
if (! is_readable("format/$format/format.php")) {
|
||||
error( "Format not known ($format)" ); }
|
||||
|
||||
// load parent class for import/export
|
||||
require("format.php");
|
||||
require_once("format.php");
|
||||
|
||||
// and then the class for the selected format
|
||||
require("format/$format/format.php");
|
||||
require_once("format/$from_form->format/format.php");
|
||||
|
||||
$classname = "qformat_$format";
|
||||
$classname = "qformat_$from_form->format";
|
||||
$qformat = new $classname();
|
||||
$qformat->setContexts($contexts->having_one_edit_tab_cap('export'));
|
||||
$qformat->setCategory($category);
|
||||
$qformat->setCourse($COURSE);
|
||||
|
||||
$qformat->setCategory( $category );
|
||||
$qformat->setCourse( $course );
|
||||
$qformat->setFilename( $exportfilename );
|
||||
$qformat->setCattofile( $cattofile );
|
||||
if (empty($from_form->exportfilename)) {
|
||||
$from_form->exportfilename = default_export_filename($COURSE, $category);
|
||||
}
|
||||
$qformat->setFilename($from_form->exportfilename);
|
||||
$qformat->setCattofile(!empty($from_form->cattofile));
|
||||
$qformat->setContexttofile(!empty($from_form->contexttofile));
|
||||
|
||||
if (! $qformat->exportpreprocess()) { // Do anything before that we need to
|
||||
error( $txt->exporterror, $thispageurl->out());
|
||||
error($txt->exporterror, $thispageurl->out());
|
||||
}
|
||||
|
||||
if (! $qformat->exportprocess()) { // Process the export data
|
||||
error( $txt->exporterror, $thispageurl->out());
|
||||
error($txt->exporterror, $thispageurl->out());
|
||||
}
|
||||
|
||||
if (! $qformat->exportpostprocess()) { // In case anything needs to be done after
|
||||
error( $txt->exporterror, $thispageurl->out());
|
||||
error($txt->exporterror, $thispageurl->out());
|
||||
}
|
||||
echo "<hr />";
|
||||
|
||||
// link to download the finished file
|
||||
$file_ext = $qformat->export_file_extension();
|
||||
if ($CFG->slasharguments) {
|
||||
$efile = "{$CFG->wwwroot}/file.php/".$qformat->question_get_export_dir()."/$exportfilename".$file_ext."?forcedownload=1";
|
||||
$efile = "{$CFG->wwwroot}/file.php/".$qformat->question_get_export_dir()."/$from_form->exportfilename".$file_ext."?forcedownload=1";
|
||||
}
|
||||
else {
|
||||
$efile = "{$CFG->wwwroot}/file.php?file=/".$qformat->question_get_export_dir()."/$exportfilename".$file_ext."&forcedownload=1";
|
||||
$efile = "{$CFG->wwwroot}/file.php?file=/".$qformat->question_get_export_dir()."/$from_form->exportfilename".$file_ext."&forcedownload=1";
|
||||
}
|
||||
echo "<p><div class=\"boxaligncenter\"><a href=\"$efile\">$txt->download</a></div></p>";
|
||||
echo "<p><div class=\"boxaligncenter\"><font size=\"-1\">$txt->downloadextra</font></div></p>";
|
||||
|
||||
print_continue("edit.php?".$thispageurl->get_query_string());
|
||||
print_footer($course);
|
||||
print_footer($COURSE);
|
||||
exit;
|
||||
}
|
||||
|
||||
/// Display upload form
|
||||
/// Display export form
|
||||
|
||||
// get valid formats to generate dropdown list
|
||||
$fileformatnames = get_import_export_formats( 'export' );
|
||||
|
||||
// get filename
|
||||
if (empty($exportfilename)) {
|
||||
$exportfilename = default_export_filename($course, $category);
|
||||
}
|
||||
|
||||
print_heading_with_help($txt->exportquestions, 'export', 'quiz');
|
||||
print_simple_box_start('center');
|
||||
?>
|
||||
|
||||
<form enctype="multipart/form-data" method="post" action="export.php">
|
||||
<fieldset class="invisiblefieldset" style="display: block;">
|
||||
<input type="hidden" name="sesskey" value="<?php echo sesskey(); ?>" />
|
||||
<?php echo $thispageurl->hidden_params_out(array(), 3); ?>
|
||||
<table cellpadding="5">
|
||||
<tr>
|
||||
<td align="right"><?php echo $txt->category; ?>:</td>
|
||||
<td>
|
||||
<?php
|
||||
question_category_select_menu($course->id, true, false, $category->id);
|
||||
echo $txt->tofile; ?>
|
||||
<input name="cattofile" type="checkbox" />
|
||||
<?php helpbutton('exportcategory', $txt->exportcategory, 'quiz'); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right"><?php echo $txt->fileformat; ?>:</td>
|
||||
<td>
|
||||
<?php choose_from_menu($fileformatnames, 'format', 'gift', '');
|
||||
helpbutton('export', $txt->exportquestions, 'quiz'); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right"><?php echo $txt->exportname; ?>:</td>
|
||||
<td>
|
||||
<input type="text" size="40" name="exportfilename" value="<?php echo $exportfilename; ?>" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" >
|
||||
<input type="submit" name="save" value="<?php echo $txt->exportquestions; ?>" />
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
</form>
|
||||
<?php
|
||||
|
||||
print_simple_box_end();
|
||||
print_footer($course);
|
||||
|
||||
$export_form->display();
|
||||
|
||||
print_footer($COURSE);
|
||||
?>
|
||||
|
||||
|
|
|
@ -16,10 +16,14 @@ class qformat_default {
|
|||
var $filename = '';
|
||||
var $matchgrades = 'error';
|
||||
var $catfromfile = 0;
|
||||
var $contextfromfile = 0;
|
||||
var $cattofile = 0;
|
||||
var $contexttofile = 0;
|
||||
var $questionids = array();
|
||||
var $importerrors = 0;
|
||||
var $stoponerror = true;
|
||||
var $translator = null;
|
||||
|
||||
|
||||
// functions to indicate import/export functionality
|
||||
// override to return true if implemented
|
||||
|
@ -49,6 +53,14 @@ class qformat_default {
|
|||
function setCourse( $course ) {
|
||||
$this->course = $course;
|
||||
}
|
||||
/**
|
||||
* set an array of contexts.
|
||||
* @param array $contexts Moodle course variable
|
||||
*/
|
||||
function setContexts($contexts) {
|
||||
$this->contexts = $contexts;
|
||||
$this->translator = new context_to_string_translator($this->contexts);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the filename
|
||||
|
@ -74,6 +86,14 @@ class qformat_default {
|
|||
$this->catfromfile = $catfromfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* set contextfromfile
|
||||
* @param bool $contextfromfile allow contexts embedded in import file
|
||||
*/
|
||||
function setContextfromfile($contextfromfile) {
|
||||
$this->contextfromfile = $contextfromfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* set cattofile
|
||||
* @param bool cattofile exports categories within export file
|
||||
|
@ -81,6 +101,13 @@ class qformat_default {
|
|||
function setCattofile( $cattofile ) {
|
||||
$this->cattofile = $cattofile;
|
||||
}
|
||||
/**
|
||||
* set contexttofile
|
||||
* @param bool cattofile exports categories within export file
|
||||
*/
|
||||
function setContexttofile($contexttofile) {
|
||||
$this->contexttofile = $contexttofile;
|
||||
}
|
||||
|
||||
/**
|
||||
* set stoponerror
|
||||
|
@ -153,6 +180,7 @@ class qformat_default {
|
|||
* @return boolean success
|
||||
*/
|
||||
function importprocess() {
|
||||
global $USER;
|
||||
|
||||
// reset the timer in case file upload was slow
|
||||
@set_time_limit();
|
||||
|
@ -194,7 +222,7 @@ class qformat_default {
|
|||
if ($this->catfromfile) {
|
||||
// find/create category object
|
||||
$catpath = $question->category;
|
||||
$newcategory = create_category_path( $catpath, '/', $this->course->id );
|
||||
$newcategory = $this->create_category_path( $catpath, '/');
|
||||
if (!empty($newcategory)) {
|
||||
$this->category = $newcategory;
|
||||
}
|
||||
|
@ -231,6 +259,9 @@ class qformat_default {
|
|||
$question->category = $this->category->id;
|
||||
$question->stamp = make_unique_id_code(); // Set the unique code (not to be changed)
|
||||
|
||||
$question->createdby = $USER->id;
|
||||
$question->timecreated = time();
|
||||
|
||||
if (!$question->id = insert_record("question", $question)) {
|
||||
error( get_string('cannotinsert','quiz') );
|
||||
}
|
||||
|
@ -258,7 +289,57 @@ class qformat_default {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* find and/or create the category described by a delimited list
|
||||
* e.g. $course$/tom/dick/harry or tom/dick/harry
|
||||
*
|
||||
* removes any context string no matter whether $getcontext is set
|
||||
* but if $getcontext is set then ignore the context and use selected category context.
|
||||
*
|
||||
* @param string catpath delimited category path
|
||||
* @param string delimiter path delimiting character
|
||||
* @param int courseid course to search for categories
|
||||
* @return mixed category object or null if fails
|
||||
*/
|
||||
function create_category_path($catpath, $delimiter='/') {
|
||||
$catpath = clean_param($catpath, PARAM_PATH);
|
||||
$catnames = explode($delimiter, $catpath);
|
||||
$parent = 0;
|
||||
$category = null;
|
||||
if (FALSE !== preg_match('/^\$([a-z]+)\$$/', $catnames[0], $matches)){
|
||||
$contextid = $this->translator->string_to_context($matches[1]);
|
||||
array_shift($catnames);
|
||||
} else {
|
||||
$contextid = FALSE;
|
||||
}
|
||||
if ($this->contextfromfile && ($contextid !== FALSE)){
|
||||
$context = get_context_instance_by_id($contextid);
|
||||
require_capability('moodle/question:add', $context);
|
||||
} else {
|
||||
$context = get_context_instance_by_id($this->category->contextid);
|
||||
}
|
||||
foreach ($catnames as $catname) {
|
||||
if ($category = get_record( 'question_categories', 'name', $catname, 'contextid', $context->id, 'parent', $parent)) {
|
||||
$parent = $category->id;
|
||||
} else {
|
||||
require_capability('moodle/question:managecategory', $context);
|
||||
// create the new category
|
||||
$category = new object;
|
||||
$category->contextid = $context->id;
|
||||
$category->name = $catname;
|
||||
$category->info = '';
|
||||
$category->parent = $parent;
|
||||
$category->sortorder = 999;
|
||||
$category->stamp = make_unique_id_code();
|
||||
if (!($id = insert_record('question_categories', $category))) {
|
||||
error( "cannot create new category - $catname" );
|
||||
}
|
||||
$category->id = $id;
|
||||
$parent = $id;
|
||||
}
|
||||
}
|
||||
return $category;
|
||||
}
|
||||
/**
|
||||
* Return complete file within an array, one item per line
|
||||
* @param string filename name of file
|
||||
|
@ -526,7 +607,7 @@ class qformat_default {
|
|||
if ($this->cattofile) {
|
||||
if ($question->category != $trackcategory) {
|
||||
$trackcategory = $question->category;
|
||||
$categoryname = get_category_path( $trackcategory );
|
||||
$categoryname = $this->get_category_path($trackcategory, '/', $this->contexttofile);
|
||||
|
||||
// create 'dummy' question for category export
|
||||
$dummyquestion = new object;
|
||||
|
@ -559,6 +640,35 @@ class qformat_default {
|
|||
fclose($fh);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* get the category as a path (e.g., tom/dick/harry)
|
||||
* @param int id the id of the most nested catgory
|
||||
* @param string delimiter the delimiter you want
|
||||
* @return string the path
|
||||
*/
|
||||
function get_category_path($id, $delimiter='/', $includecontext = true) {
|
||||
$path = '';
|
||||
if (!$firstcategory = get_record('question_categories','id',$id)) {
|
||||
print_error( "Error getting category record from db - $id" );
|
||||
}
|
||||
$category = $firstcategory;
|
||||
$contextstring = $this->translator->context_to_string($category->contextid);
|
||||
do {
|
||||
$name = $category->name;
|
||||
$id = $category->parent;
|
||||
if (!empty($path)) {
|
||||
$path = "{$name}{$delimiter}{$path}";
|
||||
}
|
||||
else {
|
||||
$path = $name;
|
||||
}
|
||||
} while ($category = get_record( 'question_categories','id',$id ));
|
||||
|
||||
if ($includecontext){
|
||||
$path = '$'.$contextstring.'$'."{$delimiter}{$path}";
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do an post-processing that may be required
|
||||
|
@ -579,7 +689,6 @@ class qformat_default {
|
|||
// if not overidden, then this is an error.
|
||||
$formatnotimplemented = get_string( 'formatnotimplemented','quiz' );
|
||||
echo "<p>$formatnotimplemented</p>";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -608,6 +717,8 @@ class qformat_default {
|
|||
}
|
||||
return format_text(stripslashes($question->questiontext), $format, $formatoptions);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
|
@ -25,8 +25,8 @@ class qformat_coursetestmanager extends qformat_default {
|
|||
}
|
||||
|
||||
function importprocess($filename) {
|
||||
global $CFG,$strimportquestions,$form,$question_category,$category,$course,
|
||||
$hostname, $mdapath, $mdbpath;
|
||||
global $CFG, $USER, $strimportquestions,$form,$question_category,$category,$course,
|
||||
$hostname, $mdapath, $mdbpath;
|
||||
if ((PHP_OS == "Linux") and isset($hostname)) {
|
||||
$hostname = trim($hostname);
|
||||
// test the ODBC socket server connection
|
||||
|
@ -261,6 +261,8 @@ class qformat_coursetestmanager extends qformat_default {
|
|||
echo "<hr /><p><b>$count</b>. ".stripslashes($question->questiontext)."</p>";
|
||||
$question->category = $this->category->id;
|
||||
$question->stamp = make_unique_id_code(); // Set the unique code (not to be changed)
|
||||
$question->createdby = $USER->id;
|
||||
$question->timecreated = time();
|
||||
if (!$question->id = insert_record("question", $question)) {
|
||||
error("Could not insert new question!");
|
||||
}
|
||||
|
|
|
@ -10,92 +10,53 @@
|
|||
*/
|
||||
|
||||
require_once("../config.php");
|
||||
require_once("editlib.php" );
|
||||
require_once("editlib.php");
|
||||
require_once($CFG->libdir . '/uploadlib.php');
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once("import_form.php");
|
||||
|
||||
list($thispageurl, $courseid, $cmid, $cm, $module, $pagevars) = question_edit_setup(false, false);
|
||||
list($thispageurl, $contexts, $cmid, $cm, $module, $pagevars) = question_edit_setup('import', false, false);
|
||||
|
||||
// get parameters
|
||||
$params = new stdClass;
|
||||
$params->choosefile = optional_param('choosefile','',PARAM_PATH);
|
||||
$catfromfile = optional_param('catfromfile', 0, PARAM_BOOL );
|
||||
$format = optional_param('format','',PARAM_FILE);
|
||||
$params->matchgrades = optional_param('matchgrades','',PARAM_ALPHA);
|
||||
$params->stoponerror = optional_param('stoponerror', 0, PARAM_BOOL);
|
||||
$params->category = optional_param( 'category', 0, PARAM_INT );
|
||||
|
||||
// get display strings
|
||||
// get display strings
|
||||
$txt = new stdClass();
|
||||
$txt->category = get_string('category','quiz');
|
||||
$txt->choosefile = get_string('choosefile','quiz');
|
||||
$txt->file = get_string('file');
|
||||
$txt->fileformat = get_string('fileformat','quiz');
|
||||
$txt->fromfile = get_string('fromfile','quiz');
|
||||
$txt->importcategory = get_string('importcategory','quiz');
|
||||
$txt->importerror = get_string('importerror','quiz');
|
||||
$txt->importfilearea = get_string('importfilearea','quiz');
|
||||
$txt->importfileupload = get_string('importfileupload','quiz');
|
||||
$txt->importfromthisfile = get_string('importfromthisfile','quiz');
|
||||
$txt->importquestions = get_string("importquestions", "quiz");
|
||||
$txt->matchgrades = get_string('matchgrades','quiz');
|
||||
$txt->matchgradeserror = get_string('matchgradeserror','quiz');
|
||||
$txt->matchgradesnearest = get_string('matchgradesnearest','quiz');
|
||||
$txt->modulename = get_string('modulename','quiz');
|
||||
$txt->modulenameplural = get_string('modulenameplural','quiz');
|
||||
$txt->onlyteachersimport = get_string('onlyteachersimport','quiz');
|
||||
$txt->questions = get_string("questions", "quiz");
|
||||
$txt->quizzes = get_string('modulenameplural', 'quiz');
|
||||
$txt->stoponerror = get_string('stoponerror', 'quiz');
|
||||
$txt->upload = get_string('upload');
|
||||
$txt->uploadproblem = get_string('uploadproblem');
|
||||
$txt->uploadthisfile = get_string('uploadthisfile');
|
||||
|
||||
// matching options
|
||||
$matchgrades = array();
|
||||
$matchgrades['error'] = $txt->matchgradeserror;
|
||||
$matchgrades['nearest'] = $txt->matchgradesnearest;
|
||||
|
||||
// not sure where $pagevars['cat'] comes from, but it doesn't respect
|
||||
// the user's choice on the form - so this bodge
|
||||
if (empty($params->category)) {
|
||||
$params->category = $pagevars['cat'];
|
||||
}
|
||||
|
||||
if (!$category = get_record("question_categories", "id", $params->category)) {
|
||||
// if no valid category was given, use the default category
|
||||
list($catid, $catcontext) = explode(',', $pagevars['cat']);
|
||||
if (!$category = get_record("question_categories", "id", $catid)) {
|
||||
print_error('nocategory','quiz');
|
||||
}
|
||||
|
||||
// check category is valid (against THIS courseid, before we change it)
|
||||
$validcats = question_category_options( $cmid, false, true );
|
||||
if (!array_key_exists( $params->category, $validcats )) {
|
||||
print_error( 'invalidcategory', 'quiz' );
|
||||
//this page can be called without courseid or cmid in which case
|
||||
//we get the context from the category object.
|
||||
if ($contexts === null) { // need to get the course from the chosen category
|
||||
$contexts = new question_edit_contexts(get_context_instance_by_id($category->contextid));
|
||||
$thiscontext = $contexts->lowest();
|
||||
if ($thiscontext->contextlevel == CONTEXT_COURSE){
|
||||
require_login($thiscontext->instanceid, false);
|
||||
} elseif ($thiscontext->contextlevel == CONTEXT_MODULE){
|
||||
list($module, $cm) = get_module_from_cmid($thiscontext->instanceid);
|
||||
require_login($cm->course, false, $cm);
|
||||
}
|
||||
$contexts->require_one_edit_tab_cap($edittab);
|
||||
}
|
||||
|
||||
$localcourseid = $cmid;
|
||||
$courseid = $category->course;
|
||||
|
||||
if (!$course = get_record("course", "id", $courseid)) {
|
||||
error("Invalid course!");
|
||||
}
|
||||
|
||||
require_login($course->id, false);
|
||||
|
||||
$context = get_context_instance(CONTEXT_COURSE, $course->id);
|
||||
require_capability('moodle/question:import', $context);
|
||||
|
||||
// ensure the files area exists for this course
|
||||
make_upload_directory( "$course->id" );
|
||||
make_upload_directory("$COURSE->id");
|
||||
|
||||
$import_form = new question_import_form($thispageurl, array('contexts'=>$contexts->having_one_edit_tab_cap('import'),
|
||||
'defaultcategory'=>$pagevars['cat']));
|
||||
|
||||
if ($import_form->is_cancelled()){
|
||||
redirect($thispageurl);
|
||||
}
|
||||
//==========
|
||||
// PAGE HEADER
|
||||
//==========
|
||||
|
||||
if ($cm!==null) {
|
||||
$strupdatemodule = has_capability('moodle/course:manageactivities', get_context_instance(CONTEXT_COURSE, $course->id))
|
||||
? update_module_button($cm->id, $course->id, get_string('modulename', $cm->modname))
|
||||
$strupdatemodule = has_capability('moodle/course:manageactivities', get_context_instance(CONTEXT_COURSE, $COURSE->id))
|
||||
? update_module_button($cm->id, $COURSE->id, get_string('modulename', $cm->modname))
|
||||
: "";
|
||||
$navlinks = array();
|
||||
$navlinks[] = array('name' => get_string('modulenameplural', $cm->modname), 'link' => "$CFG->wwwroot/mod/{$cm->modname}/index.php?id=$course->id", 'type' => 'activity');
|
||||
|
@ -122,31 +83,25 @@
|
|||
|
||||
|
||||
// file upload form sumitted
|
||||
if (!empty($format) and confirm_sesskey() ) {
|
||||
if ($form = $import_form->get_data()) {
|
||||
|
||||
// file checks out ok
|
||||
$fileisgood = false;
|
||||
|
||||
// work out if this is an uploaded file
|
||||
// or one from the filesarea.
|
||||
if (!empty($params->choosefile)) {
|
||||
$importfile = "{$CFG->dataroot}/{$course->id}/{$params->choosefile}";
|
||||
if (!empty($form->choosefile)) {
|
||||
$importfile = "{$CFG->dataroot}/{$COURSE->id}/{$form->choosefile}";
|
||||
if (file_exists($importfile)) {
|
||||
$fileisgood = true;
|
||||
}
|
||||
else {
|
||||
notify($txt->uploadproblem);
|
||||
} else {
|
||||
error(get_string('uploadproblem', 'moodle', $form->choosefile));
|
||||
}
|
||||
} else {
|
||||
// must be upload file
|
||||
if (empty($_FILES['newfile'])) {
|
||||
notify( $txt->uploadproblem );
|
||||
}
|
||||
else if ((!is_uploaded_file($_FILES['newfile']['tmp_name']) or $_FILES['newfile']['size'] == 0)) {
|
||||
notify( $txt->uploadproblem );
|
||||
}
|
||||
else {
|
||||
$importfile = $_FILES['newfile']['tmp_name'];
|
||||
if (!$importfile = $import_form->get_importfile_name()) {
|
||||
error(get_string('uploadproblem', 'moodle'));
|
||||
}else {
|
||||
$fileisgood = true;
|
||||
}
|
||||
}
|
||||
|
@ -154,133 +109,52 @@
|
|||
// process if we are happy file is ok
|
||||
if ($fileisgood) {
|
||||
|
||||
if (! is_readable("format/$format/format.php")) {
|
||||
error( get_string('formatnotfound','quiz', $format) );
|
||||
if (! is_readable("format/$form->format/format.php")) {
|
||||
error(get_string('formatnotfound','quiz', $form->format));
|
||||
}
|
||||
|
||||
require("format.php"); // Parent class
|
||||
require("format/$format/format.php");
|
||||
require_once("format.php"); // Parent class
|
||||
require_once("format/$form->format/format.php");
|
||||
|
||||
$classname = "qformat_$format";
|
||||
$classname = "qformat_$form->format";
|
||||
$qformat = new $classname();
|
||||
|
||||
// load data into class
|
||||
$qformat->setCategory( $category );
|
||||
$qformat->setCourse( $course );
|
||||
$qformat->setFilename( $importfile );
|
||||
$qformat->setMatchgrades( $params->matchgrades );
|
||||
$qformat->setCatfromfile( $catfromfile );
|
||||
$qformat->setStoponerror( $params->stoponerror );
|
||||
$qformat->setCategory($category);
|
||||
$qformat->setContexts($contexts->having_one_edit_tab_cap('import'));
|
||||
$qformat->setCourse($COURSE);
|
||||
$qformat->setFilename($importfile);
|
||||
$qformat->setMatchgrades($form->matchgrades);
|
||||
$qformat->setCatfromfile(!empty($form->catfromfile));
|
||||
$qformat->setContextfromfile(!empty($form->contextfromfile));
|
||||
$qformat->setStoponerror($form->stoponerror);
|
||||
|
||||
// Do anything before that we need to
|
||||
if (! $qformat->importpreprocess()) {
|
||||
error( $txt->importerror, $thispageurl->out(false, array('category'=>$category->id)));
|
||||
error($txt->importerror, $thispageurl->out());
|
||||
}
|
||||
|
||||
// Process the uploaded file
|
||||
if (! $qformat->importprocess() ) {
|
||||
error( $txt->importerror, $thispageurl->out(false, array('category'=>$category->id)));
|
||||
if (! $qformat->importprocess()) {
|
||||
error($txt->importerror, $thispageurl->out());
|
||||
}
|
||||
|
||||
// In case anything needs to be done after
|
||||
if (! $qformat->importpostprocess()) {
|
||||
error( $txt->importerror, $thispageurl->out(false, array('category'=>$category->id)));
|
||||
error($txt->importerror, $thispageurl->out());
|
||||
}
|
||||
|
||||
echo "<hr />";
|
||||
print_continue("edit.php?".$thispageurl->get_query_string());
|
||||
print_footer($course);
|
||||
print_continue("edit.php?".($thispageurl->get_query_string(array('category'=>"{$qformat->category->id},{$qformat->category->contextid}"))));
|
||||
print_footer($COURSE);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/// Print upload form
|
||||
|
||||
// get list of available import formats
|
||||
$fileformatnames = get_import_export_formats( 'import' );
|
||||
|
||||
print_heading_with_help($txt->importquestions, "import", "quiz");
|
||||
|
||||
/// Get all the existing categories now
|
||||
$catmenu = question_category_options($course->id, false, true);
|
||||
|
||||
//==========
|
||||
// DISPLAY
|
||||
//==========
|
||||
|
||||
?>
|
||||
|
||||
<form id="form" enctype="multipart/form-data" method="post" action="import.php">
|
||||
<fieldset class="invisiblefieldset" style="display: block;">
|
||||
<input type="hidden" name="sesskey" value="<?php echo sesskey(); ?>" />
|
||||
<input type="hidden" name="courseid" value="<?php echo $localcourseid ?>" />
|
||||
<?php echo $thispageurl->hidden_params_out(array(), 3); ?>
|
||||
<?php print_simple_box_start("center"); ?>
|
||||
<table cellpadding="5">
|
||||
<tr>
|
||||
<td align="right"><?php echo $txt->category; ?>:</td>
|
||||
<td><?php choose_from_menu($catmenu, "category", $category->id, ""); ?>
|
||||
<?php echo $txt->fromfile; ?>
|
||||
<input name="catfromfile" type="checkbox" />
|
||||
<?php helpbutton('importcategory', $txt->importcategory, 'quiz'); ?></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="right"><?php echo $txt->fileformat; ?>:</td>
|
||||
<td><?php choose_from_menu($fileformatnames, 'format', 'gift', '');
|
||||
helpbutton("import", $txt->importquestions, 'quiz'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right"><?php echo $txt->matchgrades; ?></td>
|
||||
<td><?php choose_from_menu($matchgrades,'matchgrades',$txt->matchgradeserror,'' );
|
||||
helpbutton('matchgrades', $txt->matchgrades, 'quiz'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right"><?php echo $txt->stoponerror; ?></td>
|
||||
<td><input name="stoponerror" type="checkbox" checked="checked" />
|
||||
<?php helpbutton('stoponerror', $txt->stoponerror, 'quiz'); ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php
|
||||
print_simple_box_end();
|
||||
|
||||
print_simple_box_start('center'); ?>
|
||||
<?php echo $txt->importfileupload; ?>
|
||||
<table cellpadding="5">
|
||||
<tr>
|
||||
<td align="right"><?php echo $txt->upload; ?>:</td>
|
||||
<td><?php upload_print_form_fragment(1,array('newfile'),null,false,null,$course->maxbytes,0,false); ?></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td><input type="submit" name="save" value="<?php echo $txt->uploadthisfile; ?>" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php
|
||||
print_simple_box_end();
|
||||
|
||||
print_simple_box_start('center'); ?>
|
||||
<?php echo $txt->importfilearea; ?>
|
||||
<table cellpadding="5">
|
||||
<tr>
|
||||
<td align="right"><?php echo $txt->file; ?>:</td>
|
||||
<td><input type="text" name="choosefile" size="50" /></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td><?php button_to_popup_window ("/files/index.php?id={$course->id}&choose=form.choosefile",
|
||||
"coursefiles", $txt->choosefile, 500, 750, $txt->choosefile); ?>
|
||||
<input type="submit" name="save" value="<?php echo $txt->importfromthisfile; ?>" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php
|
||||
print_simple_box_end(); ?>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<?php
|
||||
print_footer($course);
|
||||
/// Print upload form
|
||||
$import_form->display();
|
||||
print_footer($COURSE);
|
||||
|
||||
?>
|
||||
|
|
|
@ -38,12 +38,7 @@
|
|||
$continue = false;
|
||||
}
|
||||
|
||||
require_login();
|
||||
|
||||
// this might break things in the future
|
||||
if (!isteacherinanycourse()) {
|
||||
error('This page is for teachers only');
|
||||
}
|
||||
|
||||
if (!$continue) {
|
||||
// Start a new attempt; delete the old session
|
||||
|
@ -57,20 +52,23 @@
|
|||
$url .= '&continue=1';
|
||||
redirect($url);
|
||||
}
|
||||
|
||||
if (empty($quizid)) {
|
||||
$quiz = new cmoptions;
|
||||
$quiz->id = 0;
|
||||
$quiz->review = $CFG->quiz_review;
|
||||
|
||||
} else if (!$quiz = get_record('quiz', 'id', $quizid)) {
|
||||
error("Quiz id $quizid does not exist");
|
||||
}
|
||||
|
||||
// Load the question information
|
||||
if (!$questions = get_records('question', 'id', $id)) {
|
||||
error('Could not load question');
|
||||
}
|
||||
if (empty($quizid)) {
|
||||
$quiz = new cmoptions;
|
||||
$quiz->id = 0;
|
||||
$quiz->review = $CFG->quiz_review;
|
||||
require_login_in_context($questions[$id]->contextid);
|
||||
} else if (!$quiz = get_record('quiz', 'id', $quizid)) {
|
||||
error("Quiz id $quizid does not exist");
|
||||
} else {
|
||||
require_login($quiz->course, false, get_coursemodule_from_instance('quiz', $quizid, $quiz->course));
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ($maxgrade = get_field('quiz_question_instances', 'grade', 'quiz', $quiz->id, 'question', $id)) {
|
||||
$questions[$id]->maxgrade = $maxgrade;
|
||||
} else {
|
||||
|
@ -84,10 +82,12 @@
|
|||
error("This question doesn't belong to a valid category!");
|
||||
}
|
||||
|
||||
if (!has_capability('moodle/question:manage', get_context_instance(CONTEXT_COURSE, $category->course)) and !$category->publish) {
|
||||
if (!question_has_capability_on($questions[$id], 'use', $questions[$id]->category)){
|
||||
error("You can't preview these questions!");
|
||||
}
|
||||
$quiz->course = $category->course;
|
||||
if (isset($COURSE)){
|
||||
$quiz->course = $COURSE->id;
|
||||
}
|
||||
|
||||
// Load the question type specific information
|
||||
if (!get_question_options($questions)) {
|
||||
|
|
|
@ -13,23 +13,43 @@ require_once(dirname(__FILE__) . '/editlib.php');
|
|||
require_once($CFG->libdir . '/filelib.php');
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
|
||||
$returnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
|
||||
|
||||
// Read URL parameters telling us which question to edit.
|
||||
$id = optional_param('id', 0, PARAM_INT); // question id
|
||||
$cmid = optional_param('cmid', 0, PARAM_INT);
|
||||
$qtype = optional_param('qtype', '', PARAM_FILE);
|
||||
$categoryid = optional_param('category', 0, PARAM_INT);
|
||||
|
||||
$cmid = optional_param('cmid', 0, PARAM_INT);
|
||||
$courseid = optional_param('courseid', 0, PARAM_INT);
|
||||
$wizardnow = optional_param('wizardnow', '', PARAM_ALPHA);
|
||||
$movecontext = optional_param('movecontext', 0, PARAM_BOOL);//switch to make question
|
||||
//uneditable - form is displayed to edit question only
|
||||
$returnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
|
||||
|
||||
if ($movecontext && !$id){
|
||||
print_error('questiondoesnotexist', 'question', $returnurl);
|
||||
}
|
||||
|
||||
if ($cmid){
|
||||
list($module, $cm) = get_module_from_cmid($cmid);
|
||||
} else {
|
||||
require_login($cm->course, false, $cm);
|
||||
$thiscontext = get_context_instance(CONTEXT_MODULE, $cmid);
|
||||
} elseif ($courseid) {
|
||||
require_login($courseid, false);
|
||||
$thiscontext = get_context_instance(CONTEXT_COURSE, $courseid);
|
||||
$module = null;
|
||||
$cm = null;
|
||||
} else {
|
||||
error('Need to pass courseid or cmid to this script.');
|
||||
}
|
||||
$contexts = new question_edit_contexts($thiscontext);
|
||||
|
||||
|
||||
if (!$returnurl) {
|
||||
$returnurl = "{$CFG->wwwroot}/question/edit.php?courseid={$COURSE->id}";
|
||||
}
|
||||
|
||||
// Validate the URL parameters.
|
||||
|
||||
|
||||
if ($id) {
|
||||
if (!$question = get_record('question', 'id', $id)) {
|
||||
print_error('questiondoesnotexist', 'question', $returnurl);
|
||||
|
@ -47,79 +67,139 @@ if ($id) {
|
|||
if (!$category = get_record('question_categories', 'id', $question->category)) {
|
||||
print_error('categorydoesnotexist', 'question', $returnurl);
|
||||
}
|
||||
if (!$returnurl) {
|
||||
$returnurl = "{$CFG->wwwroot}/question/edit.php?courseid={$category->course}";
|
||||
|
||||
//permissions
|
||||
$question->formoptions = new object();
|
||||
$permissionstrs = array();
|
||||
|
||||
$categorycontext = get_context_instance_by_id($category->contextid);
|
||||
$addpermission = has_capability('moodle/question:add', $categorycontext);
|
||||
|
||||
if ($id) {
|
||||
$canview = question_has_capability_on($question, 'view');
|
||||
if ($movecontext){
|
||||
$question->formoptions->canedit = false;
|
||||
$question->formoptions->canmove = (question_has_capability_on($question, 'move') && $contexts->have_cap('moodle/question:add'));
|
||||
$question->formoptions->cansaveasnew = false;
|
||||
$question->formoptions->repeatelements = false;
|
||||
$question->formoptions->movecontext = true;
|
||||
$formeditable = true;
|
||||
question_require_capability_on($question, 'view');
|
||||
} else {
|
||||
$question->formoptions->canedit = question_has_capability_on($question, 'edit');
|
||||
$question->formoptions->canmove = (question_has_capability_on($question, 'move') && $addpermission);
|
||||
$question->formoptions->cansaveasnew = (($canview ||question_has_capability_on($question, 'edit')) && $addpermission);
|
||||
$question->formoptions->repeatelements = ($question->formoptions->canedit || $question->formoptions->cansaveasnew);
|
||||
$formeditable = $question->formoptions->canedit || $question->formoptions->cansaveasnew || $question->formoptions->canmove;
|
||||
$question->formoptions->movecontext = false;
|
||||
if (!$formeditable){
|
||||
question_require_capability_on($question, 'view');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else { // creating a new question
|
||||
require_capability('moodle/question:add', $categorycontext);
|
||||
$formeditable = true;
|
||||
$question->formoptions->repeatelements = true;
|
||||
$question->formoptions->movecontext = false;
|
||||
}
|
||||
|
||||
$question->category = "$category->id,$category->contextid";
|
||||
if ($formeditable && $id){
|
||||
$question->categorymoveto = $question->category;
|
||||
}
|
||||
// Validate the question type.
|
||||
if (!isset($QTYPES[$question->qtype])) {
|
||||
print_error('unknownquestiontype', 'question', $returnurl, $question->qtype);
|
||||
}
|
||||
$CFG->pagepath = 'question/type/' . $question->qtype;
|
||||
|
||||
// Check the user is logged in and has enough premissions.
|
||||
require_login($category->course, false);
|
||||
$coursecontext = get_context_instance(CONTEXT_COURSE, $category->course);
|
||||
require_capability('moodle/question:manage', $coursecontext);
|
||||
|
||||
// Create the question editing form.
|
||||
if ($wizardnow!==''){
|
||||
if ($wizardnow!=='' && !$movecontext){
|
||||
if (!method_exists($QTYPES[$question->qtype], 'next_wizard_form')){
|
||||
print_error('missingimportantcode', 'question', $returnurl, 'wizard form definition');
|
||||
} else {
|
||||
$mform = $QTYPES[$question->qtype]->next_wizard_form('question.php', $question, $wizardnow);
|
||||
$mform = $QTYPES[$question->qtype]->next_wizard_form('question.php', $question, $wizardnow, $formeditable);
|
||||
}
|
||||
} else {
|
||||
$mform = $QTYPES[$question->qtype]->create_editing_form('question.php', $question);
|
||||
$mform = $QTYPES[$question->qtype]->create_editing_form('question.php', $question, $category, $contexts, $formeditable);
|
||||
}
|
||||
|
||||
if ($mform === null) {
|
||||
print_error('missingimportantcode', 'question', $returnurl, 'question editing form definition for "'.$question->qtype.'"');
|
||||
}
|
||||
$toform = $question; // send the question object and a few more parameters to the form
|
||||
$toform->returnurl = $returnurl;
|
||||
$toform->movecontext = $movecontext;
|
||||
if ($cm !== null){
|
||||
$toform->cmid = $cm->id;
|
||||
$toform->courseid = $cm->course;
|
||||
} else {
|
||||
$toform->courseid = $COURSE->id;
|
||||
}
|
||||
$mform->set_data($toform);
|
||||
|
||||
if ($mform->is_cancelled()){
|
||||
redirect($returnurl);
|
||||
} elseif ($data = $mform->get_data()){
|
||||
$returnurl = new moodle_url($returnurl);
|
||||
//select category that question has been saved in / moved to when we return to question bank
|
||||
if (!empty($data->categorymoveto)){
|
||||
$returnurl->param('category', $data->categorymoveto);
|
||||
} else if (!empty($data->category)){
|
||||
$returnurl->param('category', $data->category);
|
||||
}
|
||||
$returnurl = $returnurl->out();
|
||||
if (!empty($data->makecopy)) {
|
||||
$question->id = 0; // causes a new question to be created.
|
||||
$question->hidden = 0; // Copies should not be hidden
|
||||
}
|
||||
if ($movecontext){
|
||||
list($tocatid, $tocontextid) = explode(',', $data->categorymoveto);
|
||||
$tocontext = get_context_instance_by_id($tocontextid);
|
||||
require_capability('moodle/question:add', $tocontext);
|
||||
if (get_filesdir_from_context($categorycontext) != get_filesdir_from_context($tocontext)){
|
||||
$movecontexturl = new moodle_url($CFG->wwwroot.'/question/contextmoveq.php',
|
||||
array('returnurl' => $returnurl,
|
||||
'ids'=>$question->id,
|
||||
'tocatid'=> $tocatid));
|
||||
if ($cmid){
|
||||
$movecontexturl->param('cmid', $cmid);
|
||||
} else {
|
||||
$movecontexturl->param('courseid', $COURSE->id);
|
||||
}
|
||||
redirect($movecontexturl->out());
|
||||
}
|
||||
}
|
||||
$question = $QTYPES[$question->qtype]->save_question($question, $data, $COURSE, $wizardnow);
|
||||
if ($QTYPES[$qtype]->finished_edit_wizard($data)){
|
||||
if ($QTYPES[$qtype]->finished_edit_wizard($data) || $movecontext){
|
||||
|
||||
if (optional_param('inpopup', 0, PARAM_BOOL)) {
|
||||
notify(get_string('changessaved'), '');
|
||||
close_window(3);
|
||||
} else {
|
||||
redirect($returnurl);
|
||||
}
|
||||
die;
|
||||
} else {
|
||||
//useful for passing data to the next page which is not saved in the database
|
||||
$queryappend = '';
|
||||
if (isset($data->nextpageparam)){
|
||||
foreach ($data->nextpageparam as $key => $param){
|
||||
$queryappend .= "&".urlencode($key).'='.urlencode($param);
|
||||
}
|
||||
}
|
||||
$nexturlparams = array('returnurl'=>$returnurl)
|
||||
+ $data->nextpageparam;//useful for passing data to the next page which is not saved in the database
|
||||
if ($question->id) {
|
||||
$nexturl = "question.php?id=$question->id&returnurl=" . urlencode($returnurl);
|
||||
$nexturlparams['id'] = $question->id;
|
||||
} else { // only for creating new questions
|
||||
$nexturl = "question.php?category=$question->category&qtype=$question->qtype&returnurl=".urlencode($returnurl);
|
||||
$nexturlparams['category'] = $question->category;
|
||||
$nexturlparams['qtype'] =$question->qtype;
|
||||
}
|
||||
redirect($nexturl.'&wizardnow='.$data->wizard.$queryappend, '', 20);
|
||||
$nexturlparams['wizardnow'] = $data->wizard;
|
||||
$nexturl = new moodle_url('question.php', $nexturlparams);
|
||||
redirect($nexturl);
|
||||
}
|
||||
} else {
|
||||
|
||||
list($streditingquestion,) = $QTYPES[$question->qtype]->get_heading();
|
||||
if ($cm !== null) {
|
||||
$strupdatemodule = has_capability('moodle/course:manageactivities', get_context_instance(CONTEXT_COURSE, $category->course))
|
||||
? update_module_button($cm->id, $category->course, get_string('modulename', $cm->modname))
|
||||
$strupdatemodule = has_capability('moodle/course:manageactivities', get_context_instance(CONTEXT_COURSE, $COURSE->id))
|
||||
? update_module_button($cm->id, $cm->course, get_string('modulename', $cm->modname))
|
||||
: "";
|
||||
$navlinks = array();
|
||||
$navlinks[] = array('name' => get_string('modulenameplural', $cm->modname), 'link' => "$CFG->wwwroot/mod/{$cm->modname}/index.php?id=$category->course", 'type' => 'activity');
|
||||
|
@ -139,10 +219,10 @@ if ($mform->is_cancelled()){
|
|||
print_header_simple($streditingquestion, '', $navigation);
|
||||
}
|
||||
|
||||
|
||||
// Display a heading, question editing form and possibly some extra content needed for
|
||||
// for this question type.
|
||||
$QTYPES[$question->qtype]->display_question_editing_page($mform, $question, $wizardnow);
|
||||
|
||||
print_footer($COURSE);
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -85,82 +85,210 @@
|
|||
|
||||
include_once($CFG->libdir.'/questionlib.php');
|
||||
|
||||
function restore_question_categories($category,$restore) {
|
||||
|
||||
global $CFG;
|
||||
/**
|
||||
* Returns the best question category (id) found to restore one
|
||||
* question category from a backup file. Works by stamp.
|
||||
*
|
||||
* @param object $restore preferences for restoration
|
||||
* @param array $contextinfo fragment of decoded xml
|
||||
* @return object best context instance for this category to be in
|
||||
*/
|
||||
function restore_question_get_best_category_context($restore, $contextinfo) {
|
||||
switch ($contextinfo['LEVEL'][0]['#']) {
|
||||
case 'module':
|
||||
$instanceinfo = backup_getid($restore->backup_unique_code, 'course_modules', $contextinfo['INSTANCE'][0]['#']);
|
||||
$tocontext = get_context_instance(CONTEXT_MODULE, $instanceinfo->new_id);
|
||||
break;
|
||||
case 'course':
|
||||
$tocontext = get_context_instance(CONTEXT_COURSE, $restore->course_id);
|
||||
break;
|
||||
case 'coursecategory':
|
||||
//search COURSECATEGORYLEVEL steps up the course cat tree or
|
||||
//to the top of the tree if steps are exhausted.
|
||||
$catno = $contextinfo['COURSECATEGORYLEVEL'][0]['#'];
|
||||
$catid = get_field('course', 'parent', 'id', $restore->course_id);
|
||||
while ($catno > 1){
|
||||
$nextcatid = get_field('course_categories', 'parent', 'id', $catid);
|
||||
if ($nextcatid == 0){
|
||||
break;
|
||||
}
|
||||
$catid == $nextcatid;
|
||||
$catno--;
|
||||
}
|
||||
$tocontext = get_context_instance(CONTEXT_COURSECAT, $catid);
|
||||
break;
|
||||
case 'system':
|
||||
$tocontext = get_context_instance(CONTEXT_SYSTEM);
|
||||
break;
|
||||
}
|
||||
return $tocontext;
|
||||
}
|
||||
|
||||
function restore_question_categories($info, $restore) {
|
||||
$status = true;
|
||||
|
||||
//Hook to call Moodle < 1.5 Quiz Restore
|
||||
if ($restore->backup_version < 2005043000) {
|
||||
include_once($CFG->dirroot.'/mod/quiz/restorelibpre15.php');
|
||||
return quiz_restore_pre15_question_categories($category,$restore);
|
||||
//Iterate over each category
|
||||
foreach ($info as $category) {
|
||||
$status = $status && restore_question_category($category, $restore);
|
||||
}
|
||||
|
||||
//Get record from backup_ids
|
||||
$data = backup_getid($restore->backup_unique_code,"question_categories",$category->id);
|
||||
|
||||
if ($data) {
|
||||
//Now get completed xmlized object
|
||||
$info = $data->info;
|
||||
//traverse_xmlize($info); //Debug
|
||||
//print_object ($GLOBALS['traverse_array']); //Debug
|
||||
//$GLOBALS['traverse_array']=""; //Debug
|
||||
|
||||
//Now, build the question_categories record structure
|
||||
$question_cat = new stdClass;
|
||||
$question_cat->course = $restore->course_id;
|
||||
$question_cat->name = backup_todb($info['QUESTION_CATEGORY']['#']['NAME']['0']['#']);
|
||||
$question_cat->info = backup_todb($info['QUESTION_CATEGORY']['#']['INFO']['0']['#']);
|
||||
$question_cat->publish = backup_todb($info['QUESTION_CATEGORY']['#']['PUBLISH']['0']['#']);
|
||||
$question_cat->stamp = backup_todb($info['QUESTION_CATEGORY']['#']['STAMP']['0']['#']);
|
||||
$question_cat->parent = backup_todb($info['QUESTION_CATEGORY']['#']['PARENT']['0']['#']);
|
||||
$question_cat->sortorder = backup_todb($info['QUESTION_CATEGORY']['#']['SORTORDER']['0']['#']);
|
||||
|
||||
if ($catfound = restore_get_best_question_category($question_cat, $restore->course_id)) {
|
||||
$newid = $catfound;
|
||||
} else {
|
||||
if (!$question_cat->stamp) {
|
||||
$question_cat->stamp = make_unique_id_code();
|
||||
}
|
||||
$newid = insert_record ("question_categories",$question_cat);
|
||||
}
|
||||
|
||||
//Do some output
|
||||
if ($newid) {
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
echo "<li>".get_string('category', 'quiz')." \"".$question_cat->name."\"<br />";
|
||||
}
|
||||
} else {
|
||||
//We must never arrive here !!
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
echo "<li>".get_string('category', 'quiz')." \"".$question_cat->name."\" Error!<br />";
|
||||
}
|
||||
$status = false;
|
||||
}
|
||||
backup_flush(300);
|
||||
|
||||
//Here category has been created or selected, so save results in backup_ids and start with questions
|
||||
if ($newid and $status) {
|
||||
//We have the newid, update backup_ids
|
||||
backup_putid($restore->backup_unique_code,"question_categories",
|
||||
$category->id, $newid);
|
||||
//Now restore question
|
||||
$status = restore_questions ($category->id, $newid,$info,$restore);
|
||||
} else {
|
||||
$status = false;
|
||||
}
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
echo '</li>';
|
||||
}
|
||||
} else {
|
||||
echo 'Could not get backup info for question category'. $category->id;
|
||||
}
|
||||
|
||||
$status = $status && restore_recode_category_parents($restore);
|
||||
return $status;
|
||||
}
|
||||
|
||||
function restore_questions ($old_category_id,$new_category_id,$info,$restore) {
|
||||
function restore_question_category($category, $restore){
|
||||
$status = true;
|
||||
//Skip empty categories (some backups can contain them)
|
||||
if (!empty($category->id)) {
|
||||
//Get record from backup_ids
|
||||
$data = backup_getid($restore->backup_unique_code, "question_categories", $category->id);
|
||||
|
||||
if ($data) {
|
||||
//Now get completed xmlized object
|
||||
$info = $data->info;
|
||||
//traverse_xmlize($info); //Debug
|
||||
//print_object ($GLOBALS['traverse_array']); //Debug
|
||||
//$GLOBALS['traverse_array']=""; //Debug
|
||||
|
||||
//Now, build the question_categories record structure
|
||||
$question_cat = new stdClass;
|
||||
$question_cat->name = backup_todb($info['QUESTION_CATEGORY']['#']['NAME']['0']['#']);
|
||||
$question_cat->info = backup_todb($info['QUESTION_CATEGORY']['#']['INFO']['0']['#']);
|
||||
$question_cat->stamp = backup_todb($info['QUESTION_CATEGORY']['#']['STAMP']['0']['#']);
|
||||
//parent is fixed after all categories are restored and we know all the new ids.
|
||||
$question_cat->parent = backup_todb($info['QUESTION_CATEGORY']['#']['PARENT']['0']['#']);
|
||||
$question_cat->sortorder = backup_todb($info['QUESTION_CATEGORY']['#']['SORTORDER']['0']['#']);
|
||||
if (!$question_cat->stamp) {
|
||||
$question_cat->stamp = make_unique_id_code();
|
||||
}
|
||||
if (isset($info['QUESTION_CATEGORY']['#']['PUBLISH'])) {
|
||||
$course = $restore->course_id;
|
||||
$publish = backup_todb($info['QUESTION_CATEGORY']['#']['PUBLISH']['0']['#']);
|
||||
if ($publish){
|
||||
$tocontext = get_context_instance(CONTEXT_SYSTEM);
|
||||
} else {
|
||||
$tocontext = get_context_instance(CONTEXT_COURSE, $course);
|
||||
}
|
||||
} else {
|
||||
$tocontext = restore_question_get_best_category_context($restore, $info['QUESTION_CATEGORY']['#']['CONTEXT']['0']['#']);
|
||||
}
|
||||
$question_cat->contextid = $tocontext->id;
|
||||
|
||||
//does cat exist ?? if it does we check if the cat and questions already exist whether we have
|
||||
//add permission or not if we have no permission to add questions to SYSTEM or COURSECAT context
|
||||
//AND the question does not already exist then we create questions in COURSE context.
|
||||
if (!$fcat = get_record('question_categories','contextid', $question_cat->contextid, 'stamp', $question_cat->stamp)){
|
||||
//no preexisting cat
|
||||
if ((($tocontext->contextlevel == CONTEXT_SYSTEM) || ($tocontext->contextlevel == CONTEXT_COURSECAT))
|
||||
&& !has_capability('moodle/question:add', $tocontext)){
|
||||
//no preexisting cat and no permission to create questions here
|
||||
//must restore to course.
|
||||
$tocontext = get_context_instance(CONTEXT_COURSE, $restore->course_id);
|
||||
}
|
||||
$question_cat->contextid = $tocontext->id;
|
||||
if (!$fcat = get_record('question_categories','contextid', $question_cat->contextid, 'stamp', $question_cat->stamp)){
|
||||
$question_cat->id = insert_record ("question_categories", $question_cat);
|
||||
} else {
|
||||
$question_cat = $fcat;
|
||||
}
|
||||
//we'll be restoring all questions here.
|
||||
backup_putid($restore->backup_unique_code, "question_categories", $category->id, $question_cat->id);
|
||||
} else {
|
||||
$question_cat = $fcat;
|
||||
//we found an existing best category
|
||||
//but later if context is above course need to check if there are questions need creating in category
|
||||
//if we do need to create questions and permissions don't allow it create new category in course
|
||||
}
|
||||
|
||||
//Do some output
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
echo "<li>".get_string('category', 'quiz')." \"".$question_cat->name."\"<br />";
|
||||
}
|
||||
|
||||
backup_flush(300);
|
||||
|
||||
//start with questions
|
||||
if ($question_cat->id) {
|
||||
//We have the newid, update backup_ids
|
||||
//Now restore question
|
||||
$status = restore_questions($category->id, $question_cat, $info, $restore);
|
||||
} else {
|
||||
$status = false;
|
||||
}
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
echo '</li>';
|
||||
}
|
||||
} else {
|
||||
echo 'Could not get backup info for question category'. $category->id;
|
||||
}
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
||||
function restore_recode_category_parents($restore){
|
||||
global $CFG;
|
||||
$status = true;
|
||||
//Now we have to recode the parent field of each restored category
|
||||
$categories = get_records_sql("SELECT old_id, new_id
|
||||
FROM {$CFG->prefix}backup_ids
|
||||
WHERE backup_code = $restore->backup_unique_code AND
|
||||
table_name = 'question_categories'");
|
||||
if ($categories) {
|
||||
//recode all parents to point at their old parent cats no matter what context the parent is now in
|
||||
foreach ($categories as $category) {
|
||||
$restoredcategory = get_record('question_categories','id',$category->new_id);
|
||||
if ($restoredcategory->parent != 0) {
|
||||
$updateobj = new object();
|
||||
$updateobj->id = $restoredcategory->id;
|
||||
$idcat = backup_getid($restore->backup_unique_code,'question_categories',$restoredcategory->parent);
|
||||
if ($idcat->new_id) {
|
||||
$updateobj->parent = $idcat->new_id;
|
||||
} else {
|
||||
$updateobj->parent = 0;
|
||||
}
|
||||
$status = $status && update_record('question_categories', $updateobj);
|
||||
}
|
||||
}
|
||||
//now we have recoded all parents, check through all parents and set parent to be
|
||||
//grand parent / great grandparent etc where there is one in same context
|
||||
//or else set parent to 0 (top level category).
|
||||
$toupdate = array();
|
||||
foreach ($categories as $category) {
|
||||
$restoredcategory = get_record('question_categories','id',$category->new_id);
|
||||
if ($restoredcategory->parent != 0) {
|
||||
$nextparentid = $restoredcategory->parent;
|
||||
do {
|
||||
if (!$parent = get_record('question_categories', 'id', $nextparentid)){
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
echo 'Could not find parent for question category '. $category->id.' recoding as top category item.<br />';
|
||||
}
|
||||
break;//record fetch failed finish loop
|
||||
} else {
|
||||
$nextparentid = $nextparent->parent;
|
||||
}
|
||||
} while (($nextparentid != 0) && ($parent->contextid != $restoredcategory->contextid));
|
||||
if (!$parent || ($parent->id != $restoredcategory->parent)){
|
||||
//change needs to be made to the parent field.
|
||||
if ($parent && ($parent->contextid == $restoredcategory->contextid)){
|
||||
$toupdate[$restoredcategory->id] = $parent->id;
|
||||
} else {
|
||||
//searched up the tree till we came to the top and did not find cat in same
|
||||
//context or there was an error getting next parent record
|
||||
$toupdate[$restoredcategory->id] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//now finally do the changes to parent field.
|
||||
foreach ($toupdate as $id => $parent){
|
||||
$updateobj = new object();
|
||||
$updateobj->id = $id;
|
||||
$updateobj->parent = $parent;
|
||||
$status = $status && update_record('question_categories', $updateobj);
|
||||
}
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
||||
function restore_questions ($old_category_id, $best_question_cat, $info, $restore) {
|
||||
|
||||
global $CFG, $QTYPES;
|
||||
|
||||
|
@ -186,7 +314,6 @@
|
|||
|
||||
//Now, build the question record structure
|
||||
$question = new object;
|
||||
$question->category = $new_category_id;
|
||||
$question->parent = backup_todb($que_info['#']['PARENT']['0']['#']);
|
||||
$question->name = backup_todb($que_info['#']['NAME']['0']['#']);
|
||||
$question->questiontext = backup_todb($que_info['#']['QUESTIONTEXT']['0']['#']);
|
||||
|
@ -204,6 +331,10 @@
|
|||
$question->stamp = backup_todb($que_info['#']['STAMP']['0']['#']);
|
||||
$question->version = backup_todb($que_info['#']['VERSION']['0']['#']);
|
||||
$question->hidden = backup_todb($que_info['#']['HIDDEN']['0']['#']);
|
||||
$question->timecreated = backup_todb($que_info['#']['TIMECREATED']['0']['#']);
|
||||
$question->timemodified = backup_todb($que_info['#']['TIMEMODIFIED']['0']['#']);
|
||||
$question->createdby = backup_todb($que_info['#']['CREATEDBY']['0']['#']);
|
||||
$question->modifiedby = backup_todb($que_info['#']['MODIFIEDBY']['0']['#']);
|
||||
|
||||
if ($restore->backup_version < 2006032200) {
|
||||
// The qtype was an integer that now needs to be converted to the name
|
||||
|
@ -213,36 +344,65 @@
|
|||
$question->qtype = $qtypenames[$question->qtype];
|
||||
}
|
||||
|
||||
//Check if the question exists
|
||||
//by category, stamp, and version
|
||||
$question_exists = get_record ("question","category",$question->category,
|
||||
"stamp",$question->stamp,"version",$question->version);
|
||||
|
||||
//Check if the question exists by category, stamp, and version
|
||||
//first check for the question in the context specified in backup
|
||||
$existingquestion = get_record ("question", "category", $best_question_cat->id, "stamp", $question->stamp,"version",$question->version);
|
||||
//If the question exists, only record its id
|
||||
if ($question_exists) {
|
||||
$newid = $question_exists->id;
|
||||
//always use existing question, no permissions check here
|
||||
if ($existingquestion) {
|
||||
$question = $existingquestion;
|
||||
$creatingnewquestion = false;
|
||||
//Else, create a new question
|
||||
} else {
|
||||
//The structure is equal to the db, so insert the question
|
||||
$newid = insert_record ("question",$question);
|
||||
$creatingnewquestion = true;
|
||||
//then if context above course level check permissions and if no permission
|
||||
//to restore above course level then restore to cat in course context.
|
||||
$bestcontext = get_context_instance_by_id($best_question_cat->contextid);
|
||||
if (($bestcontext->contextlevel == CONTEXT_SYSTEM || $bestcontext->contextlevel == CONTEXT_COURSECAT)
|
||||
&& !has_capability('moodle/question:add', $bestcontext)){
|
||||
if (!isset($course_question_cat)) {
|
||||
$coursecontext = get_context_instance(CONTEXT_COURSE, $restore->course_id);
|
||||
$course_question_cat = clone($best_question_cat);
|
||||
$course_question_cat->contextid = $coursecontext->id;
|
||||
//create cat if it doesn't exist
|
||||
if (!$fcat = get_record('question_categories','contextid', $course_question_cat->contextid, 'stamp', $course_question_cat->stamp)){
|
||||
$course_question_cat->id = insert_record ("question_categories", $course_question_cat);
|
||||
backup_putid($restore->backup_unique_code, "question_categories", $old_category_id, $course_question_cat->id);
|
||||
} else {
|
||||
$course_question_cat = $fcat;
|
||||
}
|
||||
//will fix category parents after all questions and categories restored. Will set parent to 0 if
|
||||
//no parent in same context.
|
||||
}
|
||||
$question->category = $course_question_cat->id;
|
||||
//does question already exist in course cat
|
||||
$existingquestion = get_record ("question", "category", $question->category, "stamp", $question->stamp, "version", $question->version);
|
||||
} else {
|
||||
//permissions ok, restore to best cat
|
||||
$question->category = $best_question_cat->id;
|
||||
}
|
||||
if (!$existingquestion){
|
||||
//The structure is equal to the db, so insert the question
|
||||
$question->id = insert_record ("question", $question);
|
||||
$creatingnewquestion = true;
|
||||
} else {
|
||||
$question = $existingquestion;
|
||||
$creatingnewquestion = false;
|
||||
}
|
||||
}
|
||||
|
||||
//Save newid to backup tables
|
||||
if ($newid) {
|
||||
if ($question->id) {
|
||||
//We have the newid, update backup_ids
|
||||
backup_putid($restore->backup_unique_code,"question",$oldid,
|
||||
$newid);
|
||||
backup_putid($restore->backup_unique_code, "question", $oldid, $question->id);
|
||||
}
|
||||
|
||||
$restored_questions[$i] = new stdClass;
|
||||
$restored_questions[$i]->newid = $newid;
|
||||
$restored_questions[$i]->newid = $question->id;
|
||||
$restored_questions[$i]->oldid = $oldid;
|
||||
$restored_questions[$i]->qtype = $question->qtype;
|
||||
$restored_questions[$i]->parent = $question->parent;
|
||||
$restored_questions[$i]->parent = $question->parent;
|
||||
$restored_questions[$i]->is_new = $creatingnewquestion;
|
||||
}
|
||||
backup_flush(300);
|
||||
|
||||
// Loop again, now all the question id mappings exist, so everything can
|
||||
// be restored.
|
||||
|
@ -757,12 +917,23 @@
|
|||
}
|
||||
$extraprocessing = array();
|
||||
|
||||
$coursemodulecontexts = array();
|
||||
$context = get_context_instance(CONTEXT_COURSE, $restore->course_id);
|
||||
$coursemodulecontexts[] = $context->id;
|
||||
$cms = get_records('course_modules', 'course', $restore->course_id, '', 'id');
|
||||
if ($cms){
|
||||
foreach ($cms as $cm){
|
||||
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
|
||||
$coursemodulecontexts[] = $context->id;
|
||||
}
|
||||
}
|
||||
$coursemodulecontextslist = join($coursemodulecontexts, ',');
|
||||
// Decode links in questions.
|
||||
if ($questions = get_records_sql('SELECT q.id, q.qtype, q.questiontext, q.generalfeedback
|
||||
FROM ' . $CFG->prefix . 'question q,
|
||||
' . $CFG->prefix . 'question_categories qc
|
||||
WHERE q.category = qc.id
|
||||
AND qc.course = ' . $restore->course_id)) {
|
||||
if ($questions = get_records_sql('SELECT q.id, q.qtype, q.questiontext, q.generalfeedback '.
|
||||
'FROM ' . $CFG->prefix . 'question q, '.
|
||||
$CFG->prefix . 'question_categories qc '.
|
||||
'WHERE q.category = qc.id '.
|
||||
'AND qc.contextid IN (' .$coursemodulecontextslist.')')) {
|
||||
|
||||
foreach ($questions as $question) {
|
||||
$questiontext = restore_decode_content_links_worker($question->questiontext, $restore);
|
||||
|
@ -800,8 +971,8 @@
|
|||
' . $CFG->prefix . 'question q,
|
||||
' . $CFG->prefix . 'question_categories qc
|
||||
WHERE qa.question = q.id
|
||||
AND q.category = qc.id
|
||||
AND qc.course = ' . $restore->course_id)) {
|
||||
AND q.category = qc.id '.
|
||||
'AND qc.contextid IN ('.$coursemodulecontextslist.')')) {
|
||||
|
||||
foreach ($answers as $answer) {
|
||||
$feedback = restore_decode_content_links_worker($answer->feedback, $restore);
|
||||
|
|
|
@ -11,16 +11,17 @@
|
|||
if (!isset($currenttab)) {
|
||||
$currenttab = '';
|
||||
}
|
||||
if (!isset($course)) {
|
||||
if (!isset($COURSE)) {
|
||||
error('No course specified');
|
||||
}
|
||||
|
||||
$tabs = array();
|
||||
$inactive = array();
|
||||
$row = array();
|
||||
questionbank_navigation_tabs($row, $context, 'courseid='.$course->id);
|
||||
questionbank_navigation_tabs($row, $contexts, 'courseid='.$COURSE->id);
|
||||
$tabs[] = $row;
|
||||
|
||||
print_tabs($tabs, $currenttab, array());
|
||||
|
||||
|
||||
?>
|
||||
|
|
|
@ -59,7 +59,8 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
$answerlengthformats = array('1' => get_string('decimalformat', 'quiz'), '2' => get_string('significantfiguresformat', 'quiz'));
|
||||
$repeated[] =& $mform->createElement('select', 'correctanswerformat', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
|
||||
|
||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'));
|
||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'),
|
||||
array('course' => $this->coursefilesid));
|
||||
$repeatedoptions['feedback']['type'] = PARAM_RAW;
|
||||
|
||||
if (isset($this->question->options)){
|
||||
|
@ -67,10 +68,14 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
} else {
|
||||
$count = 0;
|
||||
}
|
||||
$repeatsatstart = $count + 1;
|
||||
if ($this->question->formoptions->repeatelements){
|
||||
$repeatsatstart = $count + 1;
|
||||
} else {
|
||||
$repeatsatstart = $count;
|
||||
}
|
||||
$this->repeat_elements($repeated, $repeatsatstart, $repeatedoptions, 'noanswers', 'addanswers', 1, get_string('addmoreanswerblanks', 'qtype_calculated'));
|
||||
|
||||
$repeated = array();
|
||||
$repeated = array();
|
||||
$repeated[] =& $mform->createElement('header', 'unithdr', get_string('unithdr', 'qtype_numerical', '{no}'));
|
||||
|
||||
$repeated[] =& $mform->createElement('text', 'unit', get_string('unit', 'quiz'));
|
||||
|
@ -84,7 +89,11 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
} else {
|
||||
$countunits = 0;
|
||||
}
|
||||
$repeatsatstart = $countunits + 1;
|
||||
if ($this->question->formoptions->repeatelements){
|
||||
$repeatsatstart = $countunits + 1;
|
||||
} else {
|
||||
$repeatsatstart = $countunits;
|
||||
}
|
||||
$this->repeat_elements($repeated, $repeatsatstart, array(), 'nounits', 'addunits', 2, get_string('addmoreunitblanks', 'qtype_calculated', '{no}'));
|
||||
|
||||
$firstunit =& $mform->getElement('multiplier[0]');
|
||||
|
@ -158,7 +167,7 @@ class question_edit_calculated_form extends question_edit_form {
|
|||
}
|
||||
|
||||
function validation($data){
|
||||
$errors = array();
|
||||
$errors = parent::validation($data);
|
||||
//verifying for errors in {=...} in question text;
|
||||
$qtext = "";
|
||||
$qtextremaining = $data['questiontext'] ;
|
||||
|
|
|
@ -306,7 +306,8 @@ class question_dataset_dependent_questiontype extends default_questiontype {
|
|||
}
|
||||
break;
|
||||
case 'datasetdefinitions':
|
||||
$this->save_dataset_definitions($form);
|
||||
|
||||
$this->save_dataset_definitions($form);
|
||||
break;
|
||||
case 'datasetitems':
|
||||
$this->save_dataset_items($question, $form);
|
||||
|
|
|
@ -101,6 +101,15 @@ class question_dataset_dependent_definitions_form extends moodleform {
|
|||
$mform->addElement('hidden', 'category');
|
||||
$mform->setType('category', PARAM_INT);
|
||||
$mform->addElement('hidden', 'id');
|
||||
|
||||
$mform->addElement('hidden', 'courseid');
|
||||
$mform->setType('courseid', PARAM_INT);
|
||||
$mform->setDefault('courseid', 0);
|
||||
|
||||
$mform->addElement('hidden', 'cmid');
|
||||
$mform->setType('cmid', PARAM_INT);
|
||||
$mform->setDefault('cmid', 0);
|
||||
|
||||
$mform->setType('id', PARAM_INT);
|
||||
$mform->addElement('hidden', 'wizard', 'datasetitems');
|
||||
$mform->setType('wizard', PARAM_ALPHA);
|
||||
|
|
|
@ -156,6 +156,15 @@ class question_dataset_dependent_items_form extends moodleform {
|
|||
$mform->setType('qtype', PARAM_ALPHA);
|
||||
$mform->addElement('hidden', 'category');
|
||||
$mform->setType('category', PARAM_INT);
|
||||
|
||||
$mform->addElement('hidden', 'courseid');
|
||||
$mform->setType('courseid', PARAM_INT);
|
||||
$mform->setDefault('courseid', 0);
|
||||
|
||||
$mform->addElement('hidden', 'cmid');
|
||||
$mform->setType('cmid', PARAM_INT);
|
||||
$mform->setDefault('cmid', 0);
|
||||
|
||||
$mform->addElement('hidden', 'id');
|
||||
$mform->setType('id', PARAM_INT);
|
||||
$mform->addElement('hidden', 'wizard', 'datasetitems');
|
||||
|
|
|
@ -46,7 +46,7 @@ class description_qtype extends default_questiontype {
|
|||
|
||||
// For editing teachers print a link to an editing popup window
|
||||
$editlink = '';
|
||||
if (has_capability('moodle/question:manage', get_context_instance(CONTEXT_COURSE, $cmoptions->course))) {
|
||||
if (question_has_capability_on($question, 'edit')) {
|
||||
$stredit = get_string('edit');
|
||||
$linktext = '<img src="'.$CFG->pixpath.'/t/edit.gif" alt="'.$stredit.'" />';
|
||||
$editlink = link_to_popup_window('/question/question.php?id='.$question->id, $stredit, $linktext, 450, 550, $stredit, '', true);
|
||||
|
|
|
@ -28,9 +28,25 @@ class question_edit_form extends moodleform {
|
|||
*/
|
||||
var $question;
|
||||
|
||||
function question_edit_form($submiturl, $question){
|
||||
var $contexts;
|
||||
var $category;
|
||||
var $categorycontext;
|
||||
var $coursefilesid;
|
||||
|
||||
function question_edit_form($submiturl, $question, $category, $contexts, $formeditable = true){
|
||||
|
||||
$this->question = $question;
|
||||
parent::moodleform($submiturl);
|
||||
|
||||
$this->contexts = $contexts;
|
||||
|
||||
$this->category = $category;
|
||||
$this->categorycontext = get_context_instance_by_id($category->contextid);
|
||||
|
||||
//course id or site id depending on question cat context
|
||||
$this->coursefilesid = get_filesdir_from_context(get_context_instance_by_id($category->contextid));
|
||||
|
||||
parent::moodleform($submiturl, null, 'post', '', null, $formeditable);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,22 +67,53 @@ class question_edit_form extends moodleform {
|
|||
// Standard fields at the start of the form.
|
||||
$mform->addElement('header', 'generalheader', get_string("general", 'form'));
|
||||
|
||||
$mform->addElement('questioncategory', 'category', get_string('category', 'quiz'), null,
|
||||
array('courseid' => $COURSE->id, 'published' => true, 'only_editable' => true));
|
||||
if (!isset($this->question->id)){
|
||||
//adding question
|
||||
$mform->addElement('questioncategory', 'category', get_string('category', 'quiz'),
|
||||
array('contexts' => array($this->categorycontext)));
|
||||
} elseif (!($this->question->formoptions->canmove || $this->question->formoptions->cansaveasnew)){
|
||||
//editing question with no permission to move from category.
|
||||
$mform->addElement('questioncategory', 'category', get_string('category', 'quiz'),
|
||||
array('contexts' => array($this->categorycontext)));
|
||||
} elseif ($this->question->formoptions->movecontext){
|
||||
//moving question to another context.
|
||||
$mform->addElement('questioncategory', 'categorymoveto', get_string('category', 'quiz'),
|
||||
array('contexts' => $this->contexts->having_cap('moodle/question:add')));
|
||||
|
||||
$mform->addElement('text', 'name', get_string('questionname', 'quiz'),
|
||||
array('size' => 50));
|
||||
} else {
|
||||
//editing question with permission to move from category or save as new q
|
||||
$currentgrp = array();
|
||||
$currentgrp[0] =& $mform->createElement('questioncategory', 'category', get_string('categorycurrent', 'question'),
|
||||
array('contexts' => array($this->categorycontext)));
|
||||
if ($this->question->formoptions->canedit || $this->question->formoptions->cansaveasnew){
|
||||
//not move only form
|
||||
$currentgrp[1] =& $mform->createElement('checkbox', 'usecurrentcat', '', get_string('categorycurrentuse', 'question'));
|
||||
$mform->setDefault('usecurrentcat', 1);
|
||||
}
|
||||
$currentgrp[0]->freeze();
|
||||
$currentgrp[0]->setPersistantFreeze(false);
|
||||
$mform->addGroup($currentgrp, 'currentgrp', get_string('categorycurrent', 'question'), null, false);
|
||||
|
||||
$mform->addElement('questioncategory', 'categorymoveto', get_string('categorymoveto', 'question'),
|
||||
array('contexts' => array($this->categorycontext)));
|
||||
if ($this->question->formoptions->canedit || $this->question->formoptions->cansaveasnew){
|
||||
//not move only form
|
||||
$mform->disabledIf('categorymoveto', 'usecurrentcat', 'checked');
|
||||
}
|
||||
}
|
||||
|
||||
$mform->addElement('text', 'name', get_string('questionname', 'quiz'), array('size' => 50));
|
||||
$mform->setType('name', PARAM_TEXT);
|
||||
$mform->addRule('name', null, 'required', null, 'client');
|
||||
|
||||
$mform->addElement('htmleditor', 'questiontext', get_string('questiontext', 'quiz'),
|
||||
array('rows' => 15, 'course' => $COURSE->id));
|
||||
array('rows' => 15, 'course' => $this->coursefilesid));
|
||||
$mform->setType('questiontext', PARAM_RAW);
|
||||
$mform->setHelpButton('questiontext', array(array('questiontext', get_string('questiontext', 'quiz'), 'quiz'), 'richtext'), false, 'editorhelpbutton');
|
||||
$mform->addElement('format', 'questiontextformat', get_string('format'));
|
||||
|
||||
make_upload_directory("$COURSE->id"); // Just in case
|
||||
$coursefiles = get_directory_list("$CFG->dataroot/$COURSE->id", $CFG->moddata);
|
||||
make_upload_directory($this->coursefilesid); // Just in case
|
||||
$coursefiles = get_directory_list("$CFG->dataroot/$this->coursefilesid", $CFG->moddata);
|
||||
foreach ($coursefiles as $filename) {
|
||||
if (mimeinfo("icon", $filename) == "image.gif") {
|
||||
$images["$filename"] = $filename;
|
||||
|
@ -92,13 +139,33 @@ class question_edit_form extends moodleform {
|
|||
$mform->setDefault('penalty', 0.1);
|
||||
|
||||
$mform->addElement('htmleditor', 'generalfeedback', get_string('generalfeedback', 'quiz'),
|
||||
array('rows' => 10, 'course' => $COURSE->id));
|
||||
array('rows' => 10, 'course' => $this->coursefilesid));
|
||||
$mform->setType('generalfeedback', PARAM_RAW);
|
||||
$mform->setHelpButton('generalfeedback', array('generalfeedback', get_string('generalfeedback', 'quiz'), 'quiz'));
|
||||
|
||||
// Any questiontype specific fields.
|
||||
$this->definition_inner($mform);
|
||||
|
||||
|
||||
if (!empty($this->question->id)){
|
||||
$mform->addElement('header', 'createdmodifiedheader', get_string('createdmodifiedheader', 'question'));
|
||||
$a = new object();
|
||||
if (!empty($this->question->createdby)){
|
||||
$a->time = userdate($this->question->timecreated);
|
||||
$a->user = fullname(get_record('user', 'id', $this->question->createdby));
|
||||
} else {
|
||||
$a->time = get_string('unknown', 'question');
|
||||
$a->user = get_string('unknown', 'question');
|
||||
}
|
||||
$mform->addElement('static', 'created', get_string('created', 'question'), get_string('byandon', 'question', $a));
|
||||
if (!empty($this->question->modifiedby)){
|
||||
$a = new object();
|
||||
$a->time = userdate($this->question->timemodified);
|
||||
$a->user = fullname(get_record('user', 'id', $this->question->modifiedby));
|
||||
$mform->addElement('static', 'modified', get_string('modified', 'question'), get_string('byandon', 'question', $a));
|
||||
}
|
||||
}
|
||||
|
||||
// Standard fields at the end of the form.
|
||||
$mform->addElement('hidden', 'id');
|
||||
$mform->setType('id', PARAM_INT);
|
||||
|
@ -112,22 +179,46 @@ class question_edit_form extends moodleform {
|
|||
$mform->addElement('hidden', 'versioning');
|
||||
$mform->setType('versioning', PARAM_BOOL);
|
||||
|
||||
$mform->addElement('hidden', 'movecontext');
|
||||
$mform->setType('movecontext', PARAM_BOOL);
|
||||
|
||||
$mform->addElement('hidden', 'cmid');
|
||||
$mform->setType('cmid', PARAM_INT);
|
||||
$mform->setDefault('cmid', 0);
|
||||
|
||||
$mform->addElement('hidden', 'courseid');
|
||||
$mform->setType('courseid', PARAM_INT);
|
||||
$mform->setDefault('courseid', 0);
|
||||
|
||||
$mform->addElement('hidden', 'returnurl');
|
||||
$mform->setType('returnurl', PARAM_LOCALURL);
|
||||
$mform->setDefault('returnurl', '');
|
||||
$mform->setDefault('returnurl', 0);
|
||||
|
||||
$buttonarray = array();
|
||||
$buttonarray[] = &$mform->createElement('submit', 'submitbutton', get_string('savechanges'));
|
||||
if (!empty($this->question->id)) {
|
||||
$buttonarray[] = &$mform->createElement('submit', 'makecopy', get_string('makecopy', 'quiz'));
|
||||
if (!empty($this->question->id)){
|
||||
//editing / moving question
|
||||
if ($this->question->formoptions->movecontext){
|
||||
$buttonarray[] = &$mform->createElement('submit', 'submitbutton', get_string('moveq', 'question'));
|
||||
} elseif ($this->question->formoptions->canedit || $this->question->formoptions->canmove ||$this->question->formoptions->movecontext){
|
||||
$buttonarray[] = &$mform->createElement('submit', 'submitbutton', get_string('savechanges'));
|
||||
}
|
||||
if ($this->question->formoptions->cansaveasnew){
|
||||
$buttonarray[] = &$mform->createElement('submit', 'makecopy', get_string('makecopy', 'quiz'));
|
||||
}
|
||||
$buttonarray[] = &$mform->createElement('cancel');
|
||||
} else {
|
||||
// adding new question
|
||||
$buttonarray[] = &$mform->createElement('submit', 'submitbutton', get_string('savechanges'));
|
||||
$buttonarray[] = &$mform->createElement('cancel');
|
||||
}
|
||||
$buttonarray[] = &$mform->createElement('cancel');
|
||||
$mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
|
||||
$mform->closeHeaderBefore('buttonar');
|
||||
|
||||
if ($this->question->formoptions->movecontext){
|
||||
$mform->hardFreezeAllVisibleExcept(array('categorymoveto', 'buttonar'));
|
||||
} elseif ((!empty($this->question->id)) && (!($this->question->formoptions->canedit || $this->question->formoptions->cansaveasnew))){
|
||||
$mform->hardFreezeAllVisibleExcept(array('categorymoveto', 'buttonar', 'currentgrp'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -167,6 +258,7 @@ class question_edit_form extends moodleform {
|
|||
function qtype() {
|
||||
return '';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -19,7 +19,8 @@ class question_edit_essay_form extends question_edit_form {
|
|||
* @param MoodleQuickForm $mform the form being built.
|
||||
*/
|
||||
function definition_inner(&$mform) {
|
||||
$mform->addElement('htmleditor', 'feedback', get_string("feedback", "quiz"));
|
||||
$mform->addElement('htmleditor', 'feedback', get_string("feedback", "quiz"),
|
||||
array('course' => $this->coursefilesid));
|
||||
$mform->setType('feedback', PARAM_RAW);
|
||||
|
||||
$mform->addElement('hidden', 'fraction', 0);
|
||||
|
|
|
@ -36,8 +36,12 @@ class question_edit_match_form extends question_edit_form {
|
|||
} else {
|
||||
$countsubquestions = 0;
|
||||
}
|
||||
$repeatsatstart = (QUESTION_NUMANS_START > ($countsubquestions + QUESTION_NUMANS_ADD))?
|
||||
QUESTION_NUMANS_START : ($countsubquestions + QUESTION_NUMANS_ADD);
|
||||
if ($this->question->formoptions->repeatelements){
|
||||
$repeatsatstart = (QUESTION_NUMANS_START > ($countsubquestions + QUESTION_NUMANS_ADD))?
|
||||
QUESTION_NUMANS_START : ($countsubquestions + QUESTION_NUMANS_ADD);
|
||||
} else {
|
||||
$repeatsatstart = $countsubquestions;
|
||||
}
|
||||
$mform->setType('subanswer', PARAM_TEXT);
|
||||
$mform->setType('subquestion', PARAM_TEXT);
|
||||
|
||||
|
@ -67,7 +71,7 @@ class question_edit_match_form extends question_edit_form {
|
|||
}
|
||||
|
||||
function validation($data){
|
||||
$errors = array();
|
||||
$errors = parent::validation($data);
|
||||
$answers = $data['subanswers'];
|
||||
$questions = $data['subquestions'];
|
||||
$questioncount = 0;
|
||||
|
|
|
@ -646,6 +646,38 @@ class question_match_qtype extends default_questiontype {
|
|||
|
||||
return $status;
|
||||
}
|
||||
|
||||
function find_file_links($question, $courseid){
|
||||
// find links in the question_match_sub table.
|
||||
$urls = array();
|
||||
foreach ($question->options->subquestions as $subquestion) {
|
||||
$urls += question_find_file_links_from_html($subquestion->questiontext, $courseid);
|
||||
}
|
||||
|
||||
//set all the values of the array to the question object
|
||||
if ($urls){
|
||||
$urls = array_combine(array_keys($urls), array_fill(0, count($urls), array($question->id)));
|
||||
}
|
||||
$urls = array_merge_recursive($urls, parent::find_file_links($question, $courseid));
|
||||
return $urls;
|
||||
}
|
||||
|
||||
function replace_file_links($question, $fromcourseid, $tocourseid, $url, $destination){
|
||||
parent::replace_file_links($question, $fromcourseid, $tocourseid, $url, $destination);
|
||||
// replace links in the question_match_sub table.
|
||||
if (isset($question->options->subquestions)){
|
||||
foreach ($question->options->subquestions as $subquestion) {
|
||||
$subquestionchanged = false;
|
||||
$subquestion->questiontext = question_replace_file_links_in_html($subquestion->questiontext, $fromcourseid, $tocourseid, $url, $destination, $subquestionchanged);
|
||||
if ($subquestionchanged){//need to update rec in db
|
||||
if (!update_record('question_match_sub', addslashes_recursive($subquestion))) {
|
||||
error('Couldn\'t update \'question_match_sub\' record '.$subquestion->id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//// END OF CLASS ////
|
||||
|
||||
|
|
|
@ -25,15 +25,20 @@ class question_edit_missingtype_form extends question_edit_form {
|
|||
$repeated[] =& $mform->createElement('header', 'choicehdr', get_string('choiceno', 'qtype_multichoice', '{no}'));
|
||||
$repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'));
|
||||
$repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
|
||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'));
|
||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'),
|
||||
array('course' => $this->coursefilesid));
|
||||
|
||||
if (isset($this->question->options)){
|
||||
$countanswers = count($this->question->options->answers);
|
||||
} else {
|
||||
$countanswers = 0;
|
||||
}
|
||||
$repeatsatstart = (QUESTION_NUMANS_START > ($countanswers + QUESTION_NUMANS_ADD))?
|
||||
QUESTION_NUMANS_START : ($countanswers + QUESTION_NUMANS_ADD);
|
||||
if ($this->question->formoptions->repeatelements){
|
||||
$repeatsatstart = (QUESTION_NUMANS_START > ($countanswers + QUESTION_NUMANS_ADD))?
|
||||
QUESTION_NUMANS_START : ($countanswers + QUESTION_NUMANS_ADD);
|
||||
} else {
|
||||
$repeatsatstart = $countanswers;
|
||||
}
|
||||
$repeatedoptions = array();
|
||||
$repeatedoptions['fraction']['default'] = 0;
|
||||
$mform->setType('answer', PARAM_NOTAGS);
|
||||
|
@ -62,7 +67,7 @@ class question_edit_missingtype_form extends question_edit_form {
|
|||
}
|
||||
|
||||
function validation($data){
|
||||
$errors = array();
|
||||
$errors = parent::validation($data);
|
||||
$answers = $data['answer'];
|
||||
$answercount = 0;
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ class question_edit_multianswer_form extends question_edit_form {
|
|||
function validation($data){
|
||||
//TODO would be nice to parse the question text here and output some error
|
||||
//messages if there is a problem with the text.
|
||||
$errors = array();
|
||||
$errors = parent::validation($data);
|
||||
//extra check to make sure there is something in the htmlarea besides a <br />
|
||||
$questiontext= trim(strip_tags($data['questiontext']));
|
||||
if ($questiontext==''){
|
||||
|
|
|
@ -671,6 +671,7 @@ function qtype_multianswer_extract_question($text) {
|
|||
} else if(!empty($answerregs[ANSWER_REGEX_ANSWER_TYPE_MULTICHOICE])) {
|
||||
$wrapped->qtype = 'multichoice';
|
||||
$wrapped->single = 1;
|
||||
$wrapped->answernumbering = 0;
|
||||
$wrapped->correctfeedback = '';
|
||||
$wrapped->partiallycorrectfeedback = '';
|
||||
$wrapped->incorrectfeedback = '';
|
||||
|
|
|
@ -46,15 +46,20 @@ class question_edit_multichoice_form extends question_edit_form {
|
|||
$repeated[] =& $mform->createElement('header', 'choicehdr', get_string('choiceno', 'qtype_multichoice', '{no}'));
|
||||
$repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 50));
|
||||
$repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
|
||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'));
|
||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'),
|
||||
array('course' => $this->coursefilesid));
|
||||
|
||||
if (isset($this->question->options)){
|
||||
$countanswers = count($this->question->options->answers);
|
||||
} else {
|
||||
$countanswers = 0;
|
||||
}
|
||||
$repeatsatstart = (QUESTION_NUMANS_START > ($countanswers + QUESTION_NUMANS_ADD))?
|
||||
QUESTION_NUMANS_START : ($countanswers + QUESTION_NUMANS_ADD);
|
||||
if ($this->question->formoptions->repeatelements){
|
||||
$repeatsatstart = (QUESTION_NUMANS_START > ($countanswers + QUESTION_NUMANS_ADD))?
|
||||
QUESTION_NUMANS_START : ($countanswers + QUESTION_NUMANS_ADD);
|
||||
} else {
|
||||
$repeatsatstart = $countanswers;
|
||||
}
|
||||
$repeatedoptions = array();
|
||||
$repeatedoptions['fraction']['default'] = 0;
|
||||
$mform->setType('answer', PARAM_RAW);
|
||||
|
@ -62,13 +67,16 @@ class question_edit_multichoice_form extends question_edit_form {
|
|||
|
||||
$mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice'));
|
||||
|
||||
$mform->addElement('htmleditor', 'correctfeedback', get_string('correctfeedback', 'qtype_multichoice'));
|
||||
$mform->addElement('htmleditor', 'correctfeedback', get_string('correctfeedback', 'qtype_multichoice'),
|
||||
array('course' => $this->coursefilesid));
|
||||
$mform->setType('correctfeedback', PARAM_RAW);
|
||||
|
||||
$mform->addElement('htmleditor', 'partiallycorrectfeedback', get_string('partiallycorrectfeedback', 'qtype_multichoice'));
|
||||
$mform->addElement('htmleditor', 'partiallycorrectfeedback', get_string('partiallycorrectfeedback', 'qtype_multichoice'),
|
||||
array('course' => $this->coursefilesid));
|
||||
$mform->setType('partiallycorrectfeedback', PARAM_RAW);
|
||||
|
||||
$mform->addElement('htmleditor', 'incorrectfeedback', get_string('incorrectfeedback', 'qtype_multichoice'));
|
||||
$mform->addElement('htmleditor', 'incorrectfeedback', get_string('incorrectfeedback', 'qtype_multichoice'),
|
||||
array('course' => $this->coursefilesid));
|
||||
$mform->setType('incorrectfeedback', PARAM_RAW);
|
||||
|
||||
}
|
||||
|
@ -101,7 +109,7 @@ class question_edit_multichoice_form extends question_edit_form {
|
|||
}
|
||||
|
||||
function validation($data){
|
||||
$errors = array();
|
||||
$errors = parent::validation($data);
|
||||
$answers = $data['answer'];
|
||||
$answercount = 0;
|
||||
|
||||
|
|
|
@ -625,6 +625,36 @@ class question_multichoice_qtype extends default_questiontype {
|
|||
return 'ERR';
|
||||
}
|
||||
}
|
||||
|
||||
function find_file_links($question, $courseid){
|
||||
$urls = array();
|
||||
$urls = parent::find_file_links($question, $courseid);
|
||||
// find links in the question_match_sub table.
|
||||
foreach ($question->options->subquestions as $subquestion) {
|
||||
$urls += question_find_file_links_from_html($subquestion->questiontext, $courseid);
|
||||
|
||||
}
|
||||
//set all the values of the array to the question id
|
||||
if ($urls){
|
||||
$urls = array_combine(array_keys($urls), array_fill(0, count($urls), array($question->id)));
|
||||
}
|
||||
$urls = array_merge_recursive($urls, parent::find_file_links($question, $courseid));
|
||||
return $urls;
|
||||
}
|
||||
|
||||
function replace_file_links($question, $fromcourseid, $tocourseid, $url, $destination){
|
||||
parent::replace_file_links($question, $fromcourseid, $tocourseid, $url, $destination);
|
||||
// replace links in the question_match_sub table.
|
||||
$optionschanged = false;
|
||||
$question->options->correctfeedback = question_replace_file_links_in_html($question->options->correctfeedback, $fromcourseid, $tocourseid, $url, $destination, $optionschanged);
|
||||
$question->options->partiallycorrectfeedback = question_replace_file_links_in_html($question->options->partiallycorrectfeedback, $fromcourseid, $tocourseid, $url, $destination, $optionschanged);
|
||||
$question->options->incorrectfeedback = question_replace_file_links_in_html($question->options->incorrectfeedback, $fromcourseid, $tocourseid, $url, $destination, $optionschanged);
|
||||
if ($optionschanged){
|
||||
if (!update_record('question_multichoice', addslashes_recursive($question->options))) {
|
||||
error('Couldn\'t update \'question_multichoice\' record '.$question->options->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register this question type with the question bank.
|
||||
|
|
|
@ -36,7 +36,8 @@ class question_edit_numerical_form extends question_edit_form {
|
|||
$repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
|
||||
$repeatedoptions['fraction']['default'] = 0;
|
||||
|
||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'));
|
||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'),
|
||||
array('course' => $this->coursefilesid));
|
||||
$mform->setType('feedback', PARAM_RAW);
|
||||
|
||||
|
||||
|
@ -45,9 +46,12 @@ class question_edit_numerical_form extends question_edit_form {
|
|||
} else {
|
||||
$countanswers = 0;
|
||||
}
|
||||
$repeatsatstart = (QUESTION_NUMANS_START > ($countanswers + 1))?
|
||||
QUESTION_NUMANS_START : ($countanswers + 1);
|
||||
|
||||
if ($this->question->formoptions->repeatelements){
|
||||
$repeatsatstart = (QUESTION_NUMANS_START > ($countanswers + 1))?
|
||||
QUESTION_NUMANS_START : ($countanswers + 1);
|
||||
} else {
|
||||
$repeatsatstart = $countanswers;
|
||||
}
|
||||
$this->repeat_elements($repeated, $repeatsatstart, $repeatedoptions, 'noanswers', 'addanswers', 2, get_string('addmoreanswerblanks', 'qtype_numerical'));
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
@ -65,7 +69,12 @@ class question_edit_numerical_form extends question_edit_form {
|
|||
} else {
|
||||
$countunits = 0;
|
||||
}
|
||||
$repeatsatstart = $countunits + 2;
|
||||
|
||||
if ($this->question->formoptions->repeatelements){
|
||||
$repeatsatstart = $countunits + 2;
|
||||
} else {
|
||||
$repeatsatstart = $countunits;
|
||||
}
|
||||
$this->repeat_elements($repeated, $repeatsatstart, array(), 'nounits', 'addunits', 2, get_string('addmoreunitblanks', 'qtype_numerical'));
|
||||
|
||||
$firstunit =& $mform->getElement('multiplier[0]');
|
||||
|
@ -99,7 +108,7 @@ class question_edit_numerical_form extends question_edit_form {
|
|||
parent::set_data($question);
|
||||
}
|
||||
function validation($data){
|
||||
$errors = array();
|
||||
$errors = parent::validation($data);
|
||||
|
||||
// Check the answers.
|
||||
$answercount = 0;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @package questionbank
|
||||
* @subpackage questiontypes
|
||||
*//** */
|
||||
*/
|
||||
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
|
||||
|
@ -114,7 +114,7 @@ class default_questiontype {
|
|||
* @param string $submiturl passed on to the constructor call.
|
||||
* @return object an instance of the form definition, or null if one could not be found.
|
||||
*/
|
||||
function create_editing_form($submiturl, $question) {
|
||||
function create_editing_form($submiturl, $question, $category, $contexts, $formeditable) {
|
||||
global $CFG;
|
||||
require_once("{$CFG->dirroot}/question/type/edit_question_form.php");
|
||||
$definition_file = $CFG->dirroot.'/question/type/'.$this->name().'/edit_'.$this->name().'_form.php';
|
||||
|
@ -126,7 +126,7 @@ class default_questiontype {
|
|||
if (!class_exists($classname)) {
|
||||
return null;
|
||||
}
|
||||
return new $classname($submiturl, $question);
|
||||
return new $classname($submiturl, $question, $category, $contexts, $formeditable);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,8 +154,29 @@ class default_questiontype {
|
|||
* @param string $wizardnow is '' for first page.
|
||||
*/
|
||||
function display_question_editing_page(&$mform, $question, $wizardnow){
|
||||
list($heading, $langmodule) = $this->get_heading();
|
||||
list($heading, $langmodule) = $this->get_heading(empty($question->id));
|
||||
print_heading_with_help($heading, $this->name(), $langmodule);
|
||||
$permissionstrs = array();
|
||||
if (!empty($question->id)){
|
||||
if ($question->formoptions->canedit){
|
||||
$permissionstrs[] = get_string('permissionedit', 'question');
|
||||
}
|
||||
if ($question->formoptions->canmove){
|
||||
$permissionstrs[] = get_string('permissionmove', 'question');
|
||||
}
|
||||
if ($question->formoptions->cansaveasnew){
|
||||
$permissionstrs[] = get_string('permissionsaveasnew', 'question');
|
||||
}
|
||||
}
|
||||
if (!$question->formoptions->movecontext && count($permissionstrs)){
|
||||
print_heading(get_string('permissionto', 'question'), 'center', 3);
|
||||
$html = '<ul>';
|
||||
foreach ($permissionstrs as $permissionstr){
|
||||
$html .= '<li>'.$permissionstr.'</li>';
|
||||
}
|
||||
$html .= '</ul>';
|
||||
print_box($html, 'boxwidthnarrow boxaligncenter generalbox');
|
||||
}
|
||||
$mform->display();
|
||||
}
|
||||
|
||||
|
@ -164,15 +185,20 @@ class default_questiontype {
|
|||
*
|
||||
* @return array a string heading and the langmodule in which it was found.
|
||||
*/
|
||||
function get_heading(){
|
||||
function get_heading($adding = false){
|
||||
$name = $this->name();
|
||||
$langmodule = 'qtype_' . $name;
|
||||
$strheading = get_string('editing' . $name, $langmodule);
|
||||
if (!$adding){
|
||||
$strtoget = 'editing' . $name;
|
||||
} else {
|
||||
$strtoget = 'adding' . $name;
|
||||
}
|
||||
$strheading = get_string($strtoget, $langmodule);
|
||||
if ($strheading[0] == '[') {
|
||||
// Legacy behavior, if the string was not in the proper qtype_name
|
||||
// language file, look it up in the quiz one.
|
||||
$langmodule = 'quiz';
|
||||
$strheading = get_string('editing' . $name, $langmodule);
|
||||
$strheading = get_string($strtoget, $langmodule);
|
||||
}
|
||||
return array($strheading, $langmodule);
|
||||
}
|
||||
|
@ -204,14 +230,11 @@ class default_questiontype {
|
|||
* is itself an object, shown next to the form fields.
|
||||
*/
|
||||
function save_question($question, $form, $course) {
|
||||
global $USER;
|
||||
// This default implementation is suitable for most
|
||||
// question types.
|
||||
|
||||
// First, save the basic question itself
|
||||
if (!record_exists('question_categories', 'id', $form->category)) {
|
||||
print_error('categorydoesnotexist', 'question');
|
||||
}
|
||||
$question->category = $form->category;
|
||||
$question->name = trim($form->name);
|
||||
$question->questiontext = trim($form->questiontext);
|
||||
$question->questiontextformat = $form->questiontextformat;
|
||||
|
@ -247,16 +270,28 @@ class default_questiontype {
|
|||
}
|
||||
|
||||
if (!empty($question->id)) { // Question already exists
|
||||
if (isset($form->categorymoveto)){
|
||||
question_require_capability_on($question, 'move');
|
||||
list($question->categorymoveto, $movetocontextid) = explode(',', $form->categorymoveto);
|
||||
}
|
||||
if (isset($question->qtype) && $question->qtype != RANDOM){
|
||||
$question->category = $question->categorymoveto;
|
||||
}
|
||||
// keep existing unique stamp code
|
||||
$question->stamp = get_field('question', 'stamp', 'id', $question->id);
|
||||
if (!update_record("question", $question)) {
|
||||
error("Could not update question!");
|
||||
$question->modifiedby = $USER->id;
|
||||
$question->timemodified = time();
|
||||
if (!update_record('question', $question)) {
|
||||
error('Could not update question!');
|
||||
}
|
||||
} else { // Question is a new one
|
||||
// Set the unique code
|
||||
list($question->category,$contextid) = explode(',', $form->category);
|
||||
$question->stamp = make_unique_id_code();
|
||||
if (!$question->id = insert_record("question", $question)) {
|
||||
error("Could not insert new question!");
|
||||
$question->createdby = $USER->id;
|
||||
$question->timecreated = time();
|
||||
if (!$question->id = insert_record('question', $question)) {
|
||||
error('Could not insert new question!');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -703,6 +738,7 @@ class default_questiontype {
|
|||
// Core question types should not use this mechanism. Their styles
|
||||
// should be included in the standard theme.
|
||||
|
||||
|
||||
// We only do this once
|
||||
// for this question type, no matter how often this method is called.
|
||||
if ($this->already_done) {
|
||||
|
@ -782,7 +818,7 @@ class default_questiontype {
|
|||
|
||||
// For editing teachers print a link to an editing popup window
|
||||
$editlink = '';
|
||||
if ($context && has_capability('moodle/question:manage', $context)) {
|
||||
if (question_has_capability_on($question, 'edit')) {
|
||||
$stredit = get_string('edit');
|
||||
$linktext = '<img src="'.$CFG->pixpath.'/t/edit.gif" alt="'.$stredit.'" />';
|
||||
$editlink = link_to_popup_window('/question/question.php?inpopup=1&id='.$question->id, 'editquestion', $linktext, 450, 550, $stredit, '', true);
|
||||
|
@ -1345,6 +1381,111 @@ class default_questiontype {
|
|||
return format_text($text, $textformat, $formatoptions, $cmoptions === NULL ? NULL : $cmoptions->course);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find all course / site files linked from a question.
|
||||
*
|
||||
* Need to check for links to files in question_answers.answer and feedback
|
||||
* and in question table in generalfeedback and questiontext fields. Methods
|
||||
* on child classes will also check extra question specific fields.
|
||||
*
|
||||
* Needs to be overriden for child classes that have extra fields containing
|
||||
* html.
|
||||
*
|
||||
* @param string html the html to search
|
||||
* @param int courseid search for files for courseid course or set to siteid for
|
||||
* finding site files.
|
||||
* @return array of url, relative url is key and array with one item = question id as value
|
||||
* relative url is relative to course/site files directory root.
|
||||
*/
|
||||
function find_file_links($question, $courseid){
|
||||
$urls = array();
|
||||
if ($question->image != ''){
|
||||
if (substr(strtolower($question->image), 0, 7) == 'http://') {
|
||||
$matches = array();
|
||||
|
||||
//support for older questions where we have a complete url in image field
|
||||
if (preg_match('!^'.question_file_links_base_url($courseid).'(.*)!i', $question->image, $matches)){
|
||||
if ($cleanedurl = question_url_check($urls[$matches[2]])){
|
||||
$urls[$cleanedurl] = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($question->image != ''){
|
||||
if ($cleanedurl = question_url_check($question->image)){
|
||||
$urls[$cleanedurl] = null;//will be set later
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
$urls += question_find_file_links_from_html($question->questiontext, $courseid);
|
||||
$urls += question_find_file_links_from_html($question->generalfeedback, $courseid);
|
||||
if ($this->has_html_answers() && isset($question->options->answers)){
|
||||
foreach ($question->options->answers as $answerkey => $answer){
|
||||
$thisurls= question_find_file_links_from_html($answer->answer, $courseid);
|
||||
if ($thisurls){
|
||||
$urls += $thisurls;
|
||||
}
|
||||
}
|
||||
}
|
||||
//set all the values of the array to the question object
|
||||
if ($urls){
|
||||
$urls = array_combine(array_keys($urls), array_fill(0, count($urls), array($question->id)));
|
||||
}
|
||||
return $urls;
|
||||
}
|
||||
/*
|
||||
* Find all course / site files linked from a question.
|
||||
*
|
||||
* Need to check for links to files in question_answers.answer and feedback
|
||||
* and in question table in generalfeedback and questiontext fields. Methods
|
||||
* on child classes will also check extra question specific fields.
|
||||
*
|
||||
* Needs to be overriden for child classes that have extra fields containing
|
||||
* html.
|
||||
*
|
||||
* @param string html the html to search
|
||||
* @param int course search for files for courseid course or set to siteid for
|
||||
* finding site files.
|
||||
* @return array of files, file name is key and array with one item = question id as value
|
||||
*/
|
||||
function replace_file_links($question, $fromcourseid, $tocourseid, $url, $destination){
|
||||
global $CFG;
|
||||
$updateqrec = false;
|
||||
if (!empty($question->image)){
|
||||
//support for older questions where we have a complete url in image field
|
||||
if (substr(strtolower($question->image), 0, 7) == 'http://') {
|
||||
$questionimage = preg_replace('!^'.question_file_links_base_url($fromcourseid).preg_quote($url, '!').'$!i', $destination, $question->image, 1);
|
||||
} else {
|
||||
$questionimage = preg_replace('!^'.preg_quote($url, '!').'$!i', $destination, $question->image, 1);
|
||||
}
|
||||
if ($questionimage != $question->image){
|
||||
$question->image = $questionimage;
|
||||
$updateqrec = true;
|
||||
}
|
||||
}
|
||||
$question->questiontext = question_replace_file_links_in_html($question->questiontext, $fromcourseid, $tocourseid, $url, $destination, $updateqrec);
|
||||
$question->generalfeedback = question_replace_file_links_in_html($question->generalfeedback, $fromcourseid, $tocourseid, $url, $destination, $updateqrec);
|
||||
if ($updateqrec){
|
||||
if (!update_record('question', addslashes_recursive($question))){
|
||||
error ('Couldn\'t update question '.$question->name);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->has_html_answers() && isset($question->options->answers)){
|
||||
//answers that do not need updating have been unset
|
||||
foreach ($question->options->answers as $answer){
|
||||
$answerchanged = false;
|
||||
$answer->answer = question_replace_file_links_in_html($answer->answer, $fromcourseid, $tocourseid, $url, $destination, $answerchanged);
|
||||
if ($answerchanged){
|
||||
if (!update_record('question_answers', addslashes_recursive($answer))){
|
||||
error ('Couldn\'t update question ('.$question->name.') answer '.$answer->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return the best link to pass to print_error.
|
||||
* @param $cmoptions as passed in from outside.
|
||||
|
|
|
@ -32,7 +32,7 @@ class question_edit_random_form extends question_edit_form {
|
|||
$mform->addElement('header', 'generalheader', get_string("general", 'form'));
|
||||
|
||||
$mform->addElement('questioncategory', 'category', get_string('category', 'quiz'),
|
||||
array('courseid' => $COURSE->id, 'published' => true, 'only_editable' => true));
|
||||
array('contexts' => $this->contexts->having_cap('moodle/question:useall')));
|
||||
|
||||
$mform->addElement('text', 'name', get_string('questionname', 'quiz'),
|
||||
array('size' => 50));
|
||||
|
@ -57,6 +57,18 @@ class question_edit_random_form extends question_edit_form {
|
|||
$mform->addElement('hidden', 'versioning');
|
||||
$mform->setType('versioning', PARAM_BOOL);
|
||||
|
||||
$mform->addElement('hidden', 'cmid');
|
||||
$mform->setType('cmid', PARAM_INT);
|
||||
$mform->setDefault('cmid', 0);
|
||||
|
||||
$mform->addElement('hidden', 'courseid');
|
||||
$mform->setType('courseid', PARAM_INT);
|
||||
$mform->setDefault('courseid', 0);
|
||||
|
||||
$mform->addElement('hidden', 'returnurl');
|
||||
$mform->setType('returnurl', PARAM_LOCALURL);
|
||||
$mform->setDefault('returnurl', 0);
|
||||
|
||||
$buttonarray = array();
|
||||
$buttonarray[] = &$mform->createElement('submit', 'submitbutton', get_string('savechanges'));
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ class question_edit_randomsamatch_form extends question_edit_form {
|
|||
|
||||
function validation($data){
|
||||
global $QTYPES;
|
||||
$errors = array();
|
||||
$errors = parent::validation($data);
|
||||
$saquestions = $QTYPES['randomsamatch']->get_sa_candidates($data['category']);
|
||||
$numberavailable = count($saquestions);
|
||||
if ($saquestions === false){
|
||||
|
|
|
@ -31,15 +31,20 @@ class question_edit_shortanswer_form extends question_edit_form {
|
|||
$repeated[] =& $mform->createElement('header', 'answerhdr', get_string('answerno', 'qtype_shortanswer', '{no}'));
|
||||
$repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 54));
|
||||
$repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
|
||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'));
|
||||
$repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'),
|
||||
array('course' => $this->coursefilesid));
|
||||
|
||||
if (isset($this->question->options)){
|
||||
$countanswers = count($this->question->options->answers);
|
||||
} else {
|
||||
$countanswers = 0;
|
||||
}
|
||||
$repeatsatstart = (QUESTION_NUMANS_START > ($countanswers + QUESTION_NUMANS_ADD))?
|
||||
QUESTION_NUMANS_START : ($countanswers + QUESTION_NUMANS_ADD);
|
||||
if ($this->question->formoptions->repeatelements){
|
||||
$repeatsatstart = (QUESTION_NUMANS_START > ($countanswers + QUESTION_NUMANS_ADD))?
|
||||
QUESTION_NUMANS_START : ($countanswers + QUESTION_NUMANS_ADD);
|
||||
} else {
|
||||
$repeatsatstart = $countanswers;
|
||||
}
|
||||
$repeatedoptions = array();
|
||||
$mform->setType('answer', PARAM_RAW);
|
||||
$repeatedoptions['fraction']['default'] = 0;
|
||||
|
@ -65,7 +70,7 @@ class question_edit_shortanswer_form extends question_edit_form {
|
|||
parent::set_data($question);
|
||||
}
|
||||
function validation($data){
|
||||
$errors = array();
|
||||
$errors = parent::validation($data);
|
||||
$answers = $data['answer'];
|
||||
$answercount = 0;
|
||||
$maxgrade = false;
|
||||
|
|
|
@ -23,10 +23,12 @@ class question_edit_truefalse_form extends question_edit_form {
|
|||
$mform->addElement('select', 'correctanswer', get_string('correctanswer', 'qtype_truefalse'),
|
||||
array(0 => get_string('false', 'qtype_truefalse'), 1 => get_string('true', 'qtype_truefalse')));
|
||||
|
||||
$mform->addElement('htmleditor', 'feedbacktrue', get_string('feedbacktrue', 'qtype_truefalse'));
|
||||
$mform->addElement('htmleditor', 'feedbacktrue', get_string('feedbacktrue', 'qtype_truefalse'),
|
||||
array('course' => $this->coursefilesid));;
|
||||
$mform->setType('feedbacktrue', PARAM_RAW);
|
||||
|
||||
$mform->addElement('htmleditor', 'feedbackfalse', get_string('feedbackfalse', 'qtype_truefalse'));
|
||||
$mform->addElement('htmleditor', 'feedbackfalse', get_string('feedbackfalse', 'qtype_truefalse'),
|
||||
array('course' => $this->coursefilesid));
|
||||
$mform->setType('feedbackfalse', PARAM_RAW);
|
||||
|
||||
// Fix penalty factor at 1.
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* @author T.J.Hunt@open.ac.uk
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @package package_name
|
||||
*//** */
|
||||
*/
|
||||
|
||||
/**
|
||||
* This test is becuase the RQP question type was included in core
|
||||
|
@ -19,7 +19,7 @@
|
|||
* question type was never installed, or if the person has chosen to
|
||||
* manually reinstall the rqp question type from contrib.
|
||||
*
|
||||
* @param $version the version to test.
|
||||
* @param $result the result object that can be modified.
|
||||
* @return null if the test is irrelevant, or true or false depending on whether the test passes.
|
||||
*/
|
||||
function question_check_no_rqp_questions($result) {
|
||||
|
@ -70,4 +70,254 @@ function question_remove_rqp_qtype_config_string() {
|
|||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $result the result object that can be modified.
|
||||
* @return null if the test is irrelevant, or true or false depending on whether the test passes.
|
||||
*/
|
||||
function question_random_check($result){
|
||||
global $CFG;
|
||||
if ($CFG->version >= 2007081000){
|
||||
return null;//no test after upgrade seperates question cats into contexts.
|
||||
}
|
||||
if (!$toupdate = question_cwqpfs_to_update()){
|
||||
$result->setStatus(true);//pass test
|
||||
} else {
|
||||
//set the feedback string here and not in xml file since we need something
|
||||
//more complex than just a string picked from admin.php lang file
|
||||
$a = new object();
|
||||
$a->reporturl = "{$CFG->wwwroot}/{$CFG->admin}/report/question/";
|
||||
$lang = str_replace('_utf8', '', current_language());
|
||||
$a->docsurl = "{$CFG->docroot}/$lang/admin/report/question/index";
|
||||
$result->feedback_str = get_string('questioncwqpfscheck', 'admin', $a);
|
||||
$result->setStatus(false);//fail test
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
/*
|
||||
* Delete all 'random' questions that are not been used in a quiz.
|
||||
*/
|
||||
function question_delete_unused_random(){
|
||||
global $CFG;
|
||||
$tofix = array();
|
||||
$result = true;
|
||||
//delete all 'random' questions that are not been used in a quiz.
|
||||
if ($qqis = get_records_sql("SELECT q.* FROM {$CFG->prefix}question as q LEFT JOIN ".
|
||||
"({$CFG->prefix}quiz_question_instances as qqi) ".
|
||||
"ON (q.id = qqi.question) WHERE q.qtype='random' AND qqi.question IS NULL")){
|
||||
$qqilist = join(array_keys($qqis), ',');
|
||||
$result = $result && delete_records_select('question', "id IN ($qqilist)");
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
function question_cwqpfs_to_update($categories = null){
|
||||
global $CFG;
|
||||
|
||||
$tofix = array();
|
||||
$result = true;
|
||||
|
||||
//any cats with questions picking from subcats?
|
||||
if (!$cwqpfs = get_records_sql_menu("SELECT DISTINCT qc.id, 1 ".
|
||||
"FROM {$CFG->prefix}question as q, {$CFG->prefix}question_categories as qc ".
|
||||
"WHERE q.qtype='random' AND qc.id = q.category AND q.questiontext = 1")){
|
||||
return array();
|
||||
} else {
|
||||
if ($categories === null){
|
||||
$categories = get_records('question_categories');
|
||||
}
|
||||
$categorychildparents = array();
|
||||
foreach ($categories as $id => $category){
|
||||
$categorychildparents[$category->course][$id] = $category->parent;
|
||||
}
|
||||
foreach ($categories as $id => $category){
|
||||
if (FALSE !== array_key_exists($category->parent, $categorychildparents[$category->course])){
|
||||
//this is not a top level cat
|
||||
continue;//go to next category
|
||||
} else{
|
||||
$tofix += question_cwqpfs_check_children($id, $categories, $categorychildparents[$category->course], $cwqpfs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $tofix;
|
||||
}
|
||||
|
||||
function question_cwqpfs_check_children($checkid, $categories, $categorychildparents, $cwqpfs){
|
||||
$tofix = array();
|
||||
if (array_key_exists($checkid, $cwqpfs)){//cwqpfs in this cat
|
||||
$getchildren = array();
|
||||
$getchildren[] = $checkid;
|
||||
//search down tree and find all children
|
||||
while ($nextid = array_shift($getchildren)){//repeat until $getchildren
|
||||
//empty;
|
||||
$childids = array_keys($categorychildparents, $nextid);
|
||||
foreach ($childids as $childid){
|
||||
if ($categories[$childid]->publish != $categories[$checkid]->publish){
|
||||
$tofix[$childid] = $categories[$checkid]->publish;
|
||||
}
|
||||
}
|
||||
$getchildren = array_merge($getchildren, $childids);
|
||||
}
|
||||
} else { // check children for cwqpfs
|
||||
$childrentocheck = array_keys($categorychildparents, $checkid);
|
||||
foreach ($childrentocheck as $childtocheck){
|
||||
$tofix += question_cwqpfs_check_children($childtocheck, $categories, $categorychildparents, $cwqpfs);
|
||||
}
|
||||
}
|
||||
return $tofix;
|
||||
}
|
||||
|
||||
function question_category_next_parent_in($contextid, $question_categories, $id){
|
||||
$nextparent = $question_categories[$id]->parent;
|
||||
if ($nextparent == 0){
|
||||
return 0;
|
||||
} elseif (!array_key_exists($nextparent, $question_categories)){
|
||||
//finished searching up the category hierarchy. For some reason
|
||||
//the top level items is not 0. We'll return 0 though.
|
||||
return 0;
|
||||
} elseif ($contextid == $question_categories[$nextparent]->contextid){
|
||||
return $nextparent;
|
||||
} else {
|
||||
//parent is not in the same context look further up.
|
||||
return question_category_next_parent_in($contextid, $question_categories, $nextparent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check that either category parent is 0 or a category shared in the same context.
|
||||
* Fix any categories to point to grand or grand grand parent etc in the same context or 0.
|
||||
*/
|
||||
function question_category_checking($question_categories){
|
||||
//make an array that is easier to search
|
||||
$newparents = array();
|
||||
foreach ($question_categories as $id => $category){
|
||||
$newparents[$id] = question_category_next_parent_in($category->contextid, $question_categories, $id);
|
||||
}
|
||||
foreach (array_Keys($question_categories) as $id){
|
||||
$question_categories[$id]->parent = $newparents[$id];
|
||||
}
|
||||
return $question_categories;
|
||||
}
|
||||
|
||||
function question_upgrade_context_etc(){
|
||||
global $CFG;
|
||||
$result = true;
|
||||
$result = $result && question_delete_unused_random();
|
||||
|
||||
$question_categories = get_records('question_categories');
|
||||
|
||||
$tofix = question_cwqpfs_to_update($question_categories);
|
||||
foreach ($tofix as $catid => $publish){
|
||||
$question_categories[$catid]->publish = $publish;
|
||||
}
|
||||
|
||||
foreach ($question_categories as $id => $question_category){
|
||||
$course = $question_categories[$id]->course;
|
||||
unset($question_categories[$id]->course);
|
||||
if ($question_categories[$id]->publish){
|
||||
$context = get_context_instance(CONTEXT_SYSTEM);
|
||||
} else {
|
||||
$context = get_context_instance(CONTEXT_COURSE, $course);
|
||||
}
|
||||
$question_categories[$id]->contextid = $context->id;
|
||||
unset($question_categories[$id]->publish);
|
||||
}
|
||||
|
||||
$question_categories = question_category_checking($question_categories);
|
||||
|
||||
/// Define index course (not unique) to be dropped form question_categories
|
||||
$table = new XMLDBTable('question_categories');
|
||||
$index = new XMLDBIndex('course');
|
||||
$index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('course'));
|
||||
|
||||
/// Launch drop index course
|
||||
$result = $result && drop_index($table, $index);
|
||||
|
||||
/// Define field course to be dropped from question_categories
|
||||
$field = new XMLDBField('course');
|
||||
|
||||
/// Launch drop field course
|
||||
$result = $result && drop_field($table, $field);
|
||||
|
||||
/// Define field context to be added to question_categories
|
||||
$field = new XMLDBField('contextid');
|
||||
$field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'name');
|
||||
$field->comment = 'context that this category is shared in';
|
||||
|
||||
/// Launch add field context
|
||||
$result = $result && add_field($table, $field);
|
||||
|
||||
/// Define index context (not unique) to be added to question_categories
|
||||
$index = new XMLDBIndex('contextid');
|
||||
$index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('contextid'));
|
||||
$index->comment = 'links to context table';
|
||||
|
||||
/// Launch add index context
|
||||
$result = $result && add_index($table, $index);
|
||||
|
||||
$field = new XMLDBField('publish');
|
||||
|
||||
/// Launch drop field publish
|
||||
$result = $result && drop_field($table, $field);
|
||||
|
||||
|
||||
/// update table contents with previously calculated new contents.
|
||||
|
||||
foreach ($question_categories as $question_category){
|
||||
if (!$result = update_record('question_categories', $question_category)){
|
||||
notify('Couldn\'t update question_categories "'. $question_category->name .'"!');
|
||||
}
|
||||
}
|
||||
|
||||
/// Define field timecreated to be added to question
|
||||
$table = new XMLDBTable('question');
|
||||
$field = new XMLDBField('timecreated');
|
||||
$field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'hidden');
|
||||
|
||||
/// Launch add field timecreated
|
||||
$result = $result && add_field($table, $field);
|
||||
|
||||
/// Define field timemodified to be added to question
|
||||
$table = new XMLDBTable('question');
|
||||
$field = new XMLDBField('timemodified');
|
||||
$field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'timecreated');
|
||||
|
||||
/// Launch add field timemodified
|
||||
$result = $result && add_field($table, $field);
|
||||
|
||||
/// Define field createdby to be added to question
|
||||
$table = new XMLDBTable('question');
|
||||
$field = new XMLDBField('createdby');
|
||||
$field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null, 'timemodified');
|
||||
|
||||
/// Launch add field createdby
|
||||
$result = $result && add_field($table, $field);
|
||||
|
||||
/// Define field modifiedby to be added to question
|
||||
$table = new XMLDBTable('question');
|
||||
$field = new XMLDBField('modifiedby');
|
||||
$field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null, 'createdby');
|
||||
|
||||
/// Launch add field modifiedby
|
||||
$result = $result && add_field($table, $field);
|
||||
|
||||
/// Define key createdby (foreign) to be added to question
|
||||
$table = new XMLDBTable('question');
|
||||
$key = new XMLDBKey('createdby');
|
||||
$key->setAttributes(XMLDB_KEY_FOREIGN, array('createdby'), 'user', array('id'));
|
||||
|
||||
/// Launch add key createdby
|
||||
$result = $result && add_key($table, $key);
|
||||
|
||||
/// Define key modifiedby (foreign) to be added to question
|
||||
$table = new XMLDBTable('question');
|
||||
$key = new XMLDBKey('modifiedby');
|
||||
$key->setAttributes(XMLDB_KEY_FOREIGN, array('modifiedby'), 'user', array('id'));
|
||||
|
||||
/// Launch add key modifiedby
|
||||
$result = $result && add_key($table, $key);
|
||||
|
||||
return $result;
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// This is compared against the values stored in the database to determine
|
||||
// whether upgrades should be performed (see lib/db/*.php)
|
||||
|
||||
$version = 2007080903; // YYYYMMDD = date
|
||||
$version = 2007081000; // YYYYMMDD = date
|
||||
// XY = increments within a single day
|
||||
|
||||
$release = '1.9 dev'; // Human-friendly version name
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue