merging MOODLE_19_QUESTIONS with HEAD

This commit is contained in:
jamiesensei 2007-08-09 21:51:09 +00:00
parent 3bee1ead40
commit 271e6decda
47 changed files with 2807 additions and 1546 deletions

View 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().
"&amp;edit=$id&amp;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}&amp;id={$question->id}&amp;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();
?>

View file

@ -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(

View file

@ -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;
}
?>

View file

@ -2,20 +2,22 @@
/**
* A moodle form field type for question categories.
*
* @copyright &copy; 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);
}
}
?>

View file

@ -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) {

View file

@ -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">

View file

@ -19,7 +19,7 @@
function xmldb_quiz_upgrade($oldversion=0) {
global $CFG, $THEME, $db;
global $CFG, $THEME;
$result = true;

View file

@ -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()."&amp;addquestion=$questionid&amp;sesskey=".sesskey()."\"><img
src=\"$CFG->pixpath/t/moveleft.gif\" alt=\"$straddtoquiz\" /></a>&nbsp;";
@ -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&amp;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>';

View file

@ -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">&nbsp;</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>&nbsp;";
}
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>";
}

View file

@ -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>

View file

@ -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 . '&amp;quizid=' . $quiz->id, 'questionpreview',
"<img src=\"$CFG->pixpath/t/preview.gif\" class=\"iconsmall\" alt=\"$strpreview\" />",

View file

@ -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);

View file

@ -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;
}
?>

View file

@ -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);
?>

View file

@ -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 .= '&nbsp;'. $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('&nbsp;', $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>';
}
}
}
?>

View file

@ -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);
?>

View file

@ -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()."&amp;category=", $catmenu, "catmenu", $current, "", "", "", false, "self", "<strong>$strcategory</strong>");
popup_form ('edit.php?'.$pageurl->get_query_string().'&amp;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().'&amp;qtype=', $QTYPE_MENU, "addquestion", "", "choose", "", "", false, "self", "<strong>$strcreatenewquestion</strong>");
popup_form ($questionurl->out(false, array('category' => $category->id)).'&amp;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 . '&amp;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 . '&amp;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>&nbsp;";
} 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>&nbsp;";
}
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>&nbsp;";
}
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()."&amp;unhide=$question->id&amp;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 "&nbsp;<input title=\"$strselect\" type=\"checkbox\" name=\"q$question->id\" value=\"1\" />";
if ($caneditall || $canmoveall || $canuseall){
echo "&nbsp;<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>&nbsp;'.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>&nbsp;'.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();
}
}
?>

View file

@ -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>&nbsp;</td>
</tr>
</table>
</fieldset>
</form>
<?php
print_simple_box_end();
print_footer($course);
$export_form->display();
print_footer($COURSE);
?>

View file

@ -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);
}
}
?>

View file

@ -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!");
}

View file

@ -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>&nbsp;</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>&nbsp;</td>
<td><?php button_to_popup_window ("/files/index.php?id={$course->id}&amp;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);
?>

View file

@ -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 .= '&amp;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)) {

View file

@ -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);
}
?>

View file

@ -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);

View file

@ -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());
?>

View file

@ -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'] ;

View file

@ -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);

View file

@ -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);

View file

@ -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');

View file

@ -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);

View file

@ -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 '';
}
}
?>

View file

@ -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);

View file

@ -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;

View file

@ -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 ////

View file

@ -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;

View file

@ -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==''){

View file

@ -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 = '';

View file

@ -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;

View file

@ -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.

View file

@ -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;

View file

@ -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&amp;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.

View file

@ -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'));

View file

@ -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){

View file

@ -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;

View file

@ -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.

View file

@ -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;
}
?>

View file

@ -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