MDL-32240 quiz editing: check permissions questions are added.
We also check permissions when removing questions from the quiz, so that we do not let users make mistakes they cannot immediately undo.
This commit is contained in:
+23
-3
@@ -1047,10 +1047,13 @@ function question_make_default_categories($contexts) {
|
||||
} else {
|
||||
$category = question_get_default_category($context->id);
|
||||
}
|
||||
if ($preferredlevels[$context->contextlevel] > $preferredness && has_any_capability(
|
||||
array('moodle/question:usemine', 'moodle/question:useall'), $context)) {
|
||||
$thispreferredness = $preferredlevels[$context->contextlevel];
|
||||
if (has_any_capability(array('moodle/question:usemine', 'moodle/question:useall'), $context)) {
|
||||
$thispreferredness += 10;
|
||||
}
|
||||
if ($thispreferredness > $preferredness) {
|
||||
$toreturn = $category;
|
||||
$preferredness = $preferredlevels[$context->contextlevel];
|
||||
$preferredness = $thispreferredness;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1575,6 +1578,23 @@ class question_edit_contexts {
|
||||
return $this->having_one_cap(self::$caps[$tabname]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return those contexts where a user can add a question and then use it.
|
||||
*/
|
||||
public function having_add_and_use() {
|
||||
$contextswithcap = array();
|
||||
foreach ($this->allcontexts as $context) {
|
||||
if (!has_capability('moodle/question:add', $context)) {
|
||||
continue;
|
||||
}
|
||||
if (!has_any_capability(array('moodle/question:useall', 'moodle/question:usemine'), $context)) {
|
||||
continue;
|
||||
}
|
||||
$contextswithcap[] = $context;
|
||||
}
|
||||
return $contextswithcap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has at least one parent context got the cap $cap?
|
||||
*
|
||||
|
||||
@@ -44,8 +44,12 @@ $scrollpos = optional_param('scrollpos', 0, PARAM_INT);
|
||||
if (!$course = $DB->get_record('course', array('id' => $quiz->course))) {
|
||||
print_error('invalidcourseid');
|
||||
}
|
||||
//you need mod/quiz:manage in addition to question capabilities to access this page.
|
||||
// You need mod/quiz:manage in addition to question capabilities to access this page.
|
||||
// You also need the moodle/question:useall capability somewhere.
|
||||
require_capability('mod/quiz:manage', $contexts->lowest());
|
||||
if (!$contexts->having_cap('moodle/question:useall')) {
|
||||
print_error('nopermissions', '', '', 'use');
|
||||
}
|
||||
|
||||
$PAGE->set_url($thispageurl);
|
||||
|
||||
|
||||
@@ -42,13 +42,14 @@ class quiz_add_random_form extends moodleform {
|
||||
$mform =& $this->_form;
|
||||
|
||||
$contexts = $this->_customdata;
|
||||
$usablecontexts = $contexts->having_cap('moodle/question:useall');
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
$mform->addElement('header', 'categoryheader',
|
||||
get_string('randomfromexistingcategory', 'quiz'));
|
||||
|
||||
$mform->addElement('questioncategory', 'category', get_string('category'),
|
||||
array('contexts' => $contexts->all(), 'top' => false));
|
||||
array('contexts' => $usablecontexts, 'top' => false));
|
||||
|
||||
$mform->addElement('checkbox', 'includesubcategories', '', get_string('recurse', 'quiz'));
|
||||
|
||||
@@ -62,7 +63,7 @@ class quiz_add_random_form extends moodleform {
|
||||
$mform->setType('name', PARAM_MULTILANG);
|
||||
|
||||
$mform->addElement('questioncategory', 'parent', get_string('parentcategory', 'question'),
|
||||
array('contexts' => $contexts->all(), 'top' => true));
|
||||
array('contexts' => $usablecontexts, 'top' => true));
|
||||
$mform->addHelpButton('parent', 'parentcategory', 'question');
|
||||
|
||||
$mform->addElement('submit', 'newcategory',
|
||||
|
||||
+23
-12
@@ -55,14 +55,15 @@ require_once($CFG->dirroot . '/question/category_class.php');
|
||||
*/
|
||||
function module_specific_buttons($cmid, $cmoptions) {
|
||||
global $OUTPUT;
|
||||
$params = array(
|
||||
'type' => 'submit',
|
||||
'name' => 'add',
|
||||
'value' => $OUTPUT->larrow() . ' ' . get_string('addtoquiz', 'quiz'),
|
||||
);
|
||||
if ($cmoptions->hasattempts) {
|
||||
$disabled = 'disabled="disabled" ';
|
||||
} else {
|
||||
$disabled = '';
|
||||
$params['disabled'] = 'disabled';
|
||||
}
|
||||
$out = '<input type="submit" name="add" value="' . $OUTPUT->larrow() . ' ' .
|
||||
get_string('addtoquiz', 'quiz') . '" ' . $disabled . "/>\n";
|
||||
return $out;
|
||||
return html_writer::empty_tag('input', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,7 +138,9 @@ if ($quiz_reordertool > -1) {
|
||||
$quiz_reordertool = get_user_preferences('quiz_reordertab', 0);
|
||||
}
|
||||
|
||||
//will be set further down in the code
|
||||
$canaddrandom = $contexts->have_cap('moodle/question:useall');
|
||||
$canaddquestion = (bool) $contexts->having_add_and_use();
|
||||
|
||||
$quizhasattempts = quiz_has_attempts($quiz->id);
|
||||
|
||||
$PAGE->set_url($thispageurl);
|
||||
@@ -211,6 +214,7 @@ if (optional_param('repaginate', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
|
||||
if (($addquestion = optional_param('addquestion', 0, PARAM_INT)) && confirm_sesskey()) {
|
||||
// Add a single question to the current quiz
|
||||
quiz_require_question_use($addquestion);
|
||||
$addonpage = optional_param('addonpage', 0, PARAM_INT);
|
||||
quiz_add_quiz_question($addquestion, $quiz, $addonpage);
|
||||
quiz_delete_previews($quiz);
|
||||
@@ -225,6 +229,7 @@ if (optional_param('add', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
foreach ($rawdata as $key => $value) { // Parse input for question ids
|
||||
if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
|
||||
$key = $matches[1];
|
||||
quiz_require_question_use($key);
|
||||
quiz_add_quiz_question($key, $quiz);
|
||||
}
|
||||
}
|
||||
@@ -273,7 +278,11 @@ if (($deleteemptypage !== false) && confirm_sesskey()) {
|
||||
}
|
||||
|
||||
$remove = optional_param('remove', false, PARAM_INT);
|
||||
if (($remove = optional_param('remove', false, PARAM_INT)) && confirm_sesskey()) {
|
||||
if ($remove && confirm_sesskey()) {
|
||||
// Remove a question from the quiz.
|
||||
// We require the user to have the 'use' capability on the question,
|
||||
// so that then can add it back if they remove the wrong one by mistake.
|
||||
quiz_require_question_use($remove);
|
||||
quiz_remove_question($quiz, $remove);
|
||||
quiz_delete_previews($quiz);
|
||||
quiz_update_sumgrades($quiz);
|
||||
@@ -283,7 +292,9 @@ if (($remove = optional_param('remove', false, PARAM_INT)) && confirm_sesskey())
|
||||
if (optional_param('quizdeleteselected', false, PARAM_BOOL) &&
|
||||
!empty($selectedquestionids) && confirm_sesskey()) {
|
||||
foreach ($selectedquestionids as $questionid) {
|
||||
quiz_remove_question($quiz, $questionid);
|
||||
if (quiz_has_question_use($questionid)) {
|
||||
quiz_remove_question($quiz, $questionid);
|
||||
}
|
||||
}
|
||||
quiz_delete_previews($quiz);
|
||||
quiz_update_sumgrades($quiz);
|
||||
@@ -548,14 +559,14 @@ if ($quiz_reordertool) {
|
||||
echo '<div class="editq">';
|
||||
}
|
||||
|
||||
quiz_print_question_list($quiz, $thispageurl, true,
|
||||
$quiz_reordertool, $quiz_qbanktool, $quizhasattempts, $defaultcategoryobj);
|
||||
quiz_print_question_list($quiz, $thispageurl, true, $quiz_reordertool, $quiz_qbanktool,
|
||||
$quizhasattempts, $defaultcategoryobj, $canaddquestion, $canaddrandom);
|
||||
echo '</div>';
|
||||
|
||||
// Close <div class="quizcontents">:
|
||||
echo '</div>';
|
||||
|
||||
if (!$quiz_reordertool) {
|
||||
if (!$quiz_reordertool && $canaddrandom) {
|
||||
$randomform = new quiz_add_random_form(new moodle_url('/mod/quiz/addrandom.php'), $contexts);
|
||||
$randomform->set_data(array(
|
||||
'category' => $pagevars['cat'],
|
||||
|
||||
+57
-20
@@ -35,6 +35,28 @@ require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
||||
|
||||
define('NUM_QS_TO_SHOW_IN_RANDOM', 3);
|
||||
|
||||
/**
|
||||
* Verify that the question exists, and the user has permission to use it.
|
||||
* Does not return. Throws an exception if the question cannot be used.
|
||||
* @param int $questionid The id of the question.
|
||||
*/
|
||||
function quiz_require_question_use($questionid) {
|
||||
global $DB;
|
||||
$question = $DB->get_record('question', array('id' => $questionid), '*', MUST_EXIST);
|
||||
question_require_capability_on($question, 'use');
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the question exists, and the user has permission to use it.
|
||||
* @param int $questionid The id of the question.
|
||||
* @return bool whether the user can use this question.
|
||||
*/
|
||||
function quiz_has_question_use($questionid) {
|
||||
global $DB;
|
||||
$question = $DB->get_record('question', array('id' => $questionid), '*', MUST_EXIST);
|
||||
return question_has_capability_on($question, 'use');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a question from a quiz
|
||||
* @param object $quiz the quiz object.
|
||||
@@ -333,19 +355,21 @@ function quiz_move_question_down($layout, $questionid) {
|
||||
* Prints a list of quiz questions for the edit.php main view for edit
|
||||
* ($reordertool = false) and order and paging ($reordertool = true) tabs
|
||||
*
|
||||
* @return int sum of maximum grades
|
||||
* @param object $quiz This is not the standard quiz object used elsewhere but
|
||||
* it contains the quiz layout in $quiz->questions and the grades in
|
||||
* $quiz->grades
|
||||
* @param object $pageurl The url of the current page with the parameters required
|
||||
* @param moodle_url $pageurl The url of the current page with the parameters required
|
||||
* for links returning to the current page, as a moodle_url object
|
||||
* @param bool $allowdelete Indicates whether the delete icons should be displayed
|
||||
* @param bool $reordertool Indicates whether the reorder tool should be displayed
|
||||
* @param bool $quiz_qbanktool Indicates whether the question bank should be displayed
|
||||
* @param bool $hasattempts Indicates whether the quiz has attempts
|
||||
* @param object $defaultcategoryobj
|
||||
* @param bool $canaddquestion is the user able to add and use questions anywere?
|
||||
* @param bool $canaddrandom is the user able to add random questions anywere?
|
||||
*/
|
||||
function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
|
||||
$quiz_qbanktool, $hasattempts, $defaultcategoryobj) {
|
||||
$quiz_qbanktool, $hasattempts, $defaultcategoryobj, $canaddquestion, $canaddrandom) {
|
||||
global $CFG, $DB, $OUTPUT;
|
||||
$strorder = get_string('order');
|
||||
$strquestionname = get_string('questionname', 'quiz');
|
||||
@@ -667,7 +691,7 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
|
||||
if (!$reordertool && !($quiz->shufflequestions &&
|
||||
$count < $questiontotalcount - 1)) {
|
||||
quiz_print_pagecontrols($quiz, $pageurl, $pagecount,
|
||||
$hasattempts, $defaultcategoryobj);
|
||||
$hasattempts, $defaultcategoryobj, $canaddquestion, $canaddrandom);
|
||||
} else if ($count < $questiontotalcount - 1) {
|
||||
//do not include the last page break for reordering
|
||||
//to avoid creating a new extra page in the end
|
||||
@@ -703,12 +727,19 @@ function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
|
||||
* Print all the controls for adding questions directly into the
|
||||
* specific page in the edit tab of edit.php
|
||||
*
|
||||
* @param unknown_type $quiz
|
||||
* @param unknown_type $pageurl
|
||||
* @param unknown_type $page
|
||||
* @param unknown_type $hasattempts
|
||||
* @param object $quiz This is not the standard quiz object used elsewhere but
|
||||
* it contains the quiz layout in $quiz->questions and the grades in
|
||||
* $quiz->grades
|
||||
* @param moodle_url $pageurl The url of the current page with the parameters required
|
||||
* for links returning to the current page, as a moodle_url object
|
||||
* @param int $page the current page number.
|
||||
* @param bool $hasattempts Indicates whether the quiz has attempts
|
||||
* @param object $defaultcategoryobj
|
||||
* @param bool $canaddquestion is the user able to add and use questions anywere?
|
||||
* @param bool $canaddrandom is the user able to add random questions anywere?
|
||||
*/
|
||||
function quiz_print_pagecontrols($quiz, $pageurl, $page, $hasattempts, $defaultcategoryobj) {
|
||||
function quiz_print_pagecontrols($quiz, $pageurl, $page, $hasattempts,
|
||||
$defaultcategoryobj, $canaddquestion, $canaddrandom) {
|
||||
global $CFG, $OUTPUT;
|
||||
static $randombuttoncount = 0;
|
||||
$randombuttoncount++;
|
||||
@@ -724,22 +755,25 @@ function quiz_print_pagecontrols($quiz, $pageurl, $page, $hasattempts, $defaultc
|
||||
$defaultcategoryid = $defaultcategoryobj->id;
|
||||
}
|
||||
|
||||
// Create the url the question page will return to
|
||||
$returnurladdtoquiz = new moodle_url($pageurl, array('addonpage' => $page));
|
||||
if ($canaddquestion) {
|
||||
// Create the url the question page will return to
|
||||
$returnurladdtoquiz = new moodle_url($pageurl, array('addonpage' => $page));
|
||||
|
||||
// Print a button linking to the choose question type page.
|
||||
$returnurladdtoquiz = $returnurladdtoquiz->out_as_local_url(false);
|
||||
$newquestionparams = array('returnurl' => $returnurladdtoquiz,
|
||||
'cmid' => $quiz->cmid, 'appendqnumstring' => 'addquestion');
|
||||
create_new_question_button($defaultcategoryid, $newquestionparams,
|
||||
get_string('addaquestion', 'quiz'),
|
||||
get_string('createquestionandadd', 'quiz'), $hasattempts);
|
||||
// Print a button linking to the choose question type page.
|
||||
$returnurladdtoquiz = $returnurladdtoquiz->out_as_local_url(false);
|
||||
$newquestionparams = array('returnurl' => $returnurladdtoquiz,
|
||||
'cmid' => $quiz->cmid, 'appendqnumstring' => 'addquestion');
|
||||
create_new_question_button($defaultcategoryid, $newquestionparams,
|
||||
get_string('addaquestion', 'quiz'),
|
||||
get_string('createquestionandadd', 'quiz'), $hasattempts);
|
||||
}
|
||||
|
||||
if ($hasattempts) {
|
||||
$disabled = 'disabled="disabled"';
|
||||
} else {
|
||||
$disabled = '';
|
||||
}
|
||||
if ($canaddrandom) {
|
||||
?>
|
||||
<div class="singlebutton">
|
||||
<form class="randomquestionform" action="<?php echo $CFG->wwwroot;
|
||||
@@ -760,8 +794,8 @@ function quiz_print_pagecontrols($quiz, $pageurl, $page, $hasattempts, $defaultc
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php echo $OUTPUT->help_icon('addarandomquestion', 'quiz'); ?>
|
||||
<?php
|
||||
<?php echo $OUTPUT->help_icon('addarandomquestion', 'quiz');
|
||||
}
|
||||
echo "\n</div>";
|
||||
}
|
||||
|
||||
@@ -1021,6 +1055,9 @@ class question_bank_add_to_quiz_action_column extends question_bank_action_colum
|
||||
}
|
||||
|
||||
protected function display_content($question, $rowclasses) {
|
||||
if (!question_has_capability_on($question, 'use')) {
|
||||
return;
|
||||
}
|
||||
// for RTL languages: switch right and left arrows
|
||||
if (right_to_left()) {
|
||||
$movearrow = 't/removeright';
|
||||
|
||||
@@ -406,6 +406,7 @@ class question_bank_checkbox_column extends question_bank_column_base {
|
||||
echo '<input title="' . $this->strselect . '" type="checkbox" name="q' .
|
||||
$question->id . '" id="checkq' . $question->id . '" value="1"/>';
|
||||
if ($this->firstrow) {
|
||||
$PAGE->requires->js('/question/qbank.js');
|
||||
$PAGE->requires->js_function_call('question_bank.init_checkbox_column', array(get_string('selectall'),
|
||||
get_string('deselectall'), 'checkq' . $question->id));
|
||||
$this->firstrow = false;
|
||||
|
||||
@@ -188,6 +188,7 @@ if ($id) {
|
||||
$formeditable = true;
|
||||
require_capability('moodle/question:add', $categorycontext);
|
||||
}
|
||||
$question->formoptions->mustbeusable = (bool) $appendqnumstring;
|
||||
|
||||
// Validate the question type.
|
||||
$PAGE->set_pagetype('question-type-' . $question->qtype);
|
||||
|
||||
@@ -129,9 +129,15 @@ abstract class question_edit_form extends question_wizard_form {
|
||||
$mform->addElement('header', 'generalheader', get_string("general", 'form'));
|
||||
|
||||
if (!isset($this->question->id)) {
|
||||
if (!empty($this->question->formoptions->mustbeusable)) {
|
||||
$contexts = $this->contexts->having_add_and_use();
|
||||
} else {
|
||||
$contexts = $this->contexts->having_cap('moodle/question:add');
|
||||
}
|
||||
|
||||
// Adding question
|
||||
$mform->addElement('questioncategory', 'category', get_string('category', 'question'),
|
||||
array('contexts' => $this->contexts->having_cap('moodle/question:add')));
|
||||
array('contexts' => $contexts));
|
||||
} else if (!($this->question->formoptions->canmove ||
|
||||
$this->question->formoptions->cansaveasnew)) {
|
||||
// Editing question with no permission to move from category.
|
||||
|
||||
Reference in New Issue
Block a user