| [ Index ] |
PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008] |
[Summary view] [Print] [Text view]
1 <?php // $Id: editlib.php,v 1.76.2.9 2008/05/27 10:35:14 tjhunt Exp $ 2 /** 3 * Functions used to show question editing interface 4 * 5 * 6 * @author Martin Dougiamas and many others. This has recently been extensively 7 * rewritten by members of the Serving Mathematics project 8 * {@link http://maths.york.ac.uk/serving_maths} 9 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License 10 * @package questionbank 11 */ 12 13 require_once($CFG->libdir.'/questionlib.php'); 14 15 define('DEFAULT_QUESTIONS_PER_PAGE', 20); 16 17 function get_module_from_cmid($cmid){ 18 global $CFG; 19 if (!$cmrec = get_record_sql("SELECT cm.*, md.name as modname 20 FROM {$CFG->prefix}course_modules cm, 21 {$CFG->prefix}modules md 22 WHERE cm.id = '$cmid' AND 23 md.id = cm.module")){ 24 error('cmunknown'); 25 } elseif (!$modrec =get_record($cmrec->modname, 'id', $cmrec->instance)) { 26 error('cmunknown'); 27 } 28 $modrec->instance = $modrec->id; 29 $modrec->cmid = $cmrec->id; 30 $cmrec->name = $modrec->name; 31 32 return array($modrec, $cmrec); 33 } 34 /** 35 * Function to read all questions for category into big array 36 * 37 * @param int $category category number 38 * @param bool $noparent if true only questions with NO parent will be selected 39 * @param bool $recurse include subdirectories 40 * @param bool $export set true if this is called by questionbank export 41 * @author added by Howard Miller June 2004 42 */ 43 function get_questions_category( $category, $noparent=false, $recurse=true, $export=true ) { 44 45 global $QTYPES; 46 47 // questions will be added to an array 48 $qresults = array(); 49 50 // build sql bit for $noparent 51 $npsql = ''; 52 if ($noparent) { 53 $npsql = " and parent='0' "; 54 } 55 56 // get (list) of categories 57 if ($recurse) { 58 $categorylist = question_categorylist( $category->id ); 59 } 60 else { 61 $categorylist = $category->id; 62 } 63 64 // get the list of questions for the category 65 if ($questions = get_records_select("question","category IN ($categorylist) $npsql", "qtype, name ASC")) { 66 67 // iterate through questions, getting stuff we need 68 foreach($questions as $question) { 69 $questiontype = $QTYPES[$question->qtype]; 70 $question->export_process = $export; 71 $questiontype->get_question_options( $question ); 72 $qresults[] = $question; 73 } 74 } 75 76 return $qresults; 77 } 78 79 80 function question_can_delete_cat($todelete){ 81 global $CFG; 82 $record = get_record_sql("SELECT count(*) as count, c1.contextid as contextid FROM {$CFG->prefix}question_categories c1, 83 {$CFG->prefix}question_categories c2 WHERE c2.id = $todelete 84 AND c1.contextid = c2.contextid GROUP BY c1.contextid"); 85 $contextid = $record->contextid; 86 $count = $record->count; 87 if ($count < 2) { 88 error('You can\'t delete that category it is the default category for this context.'); 89 } else { 90 require_capability('moodle/question:managecategory', get_context_instance_by_id($contextid)); 91 } 92 } 93 /** 94 * prints a form to choose categories 95 */ 96 function question_category_form($contexts, $pageurl, $current, $recurse=1, $showhidden=false, $showquestiontext=false) { 97 global $CFG; 98 99 100 /// Get all the existing categories now 101 $catmenu = question_category_options($contexts, false, 0, true); 102 103 $strcategory = get_string('category', 'quiz'); 104 $strshow = get_string('show', 'quiz'); 105 $streditcats = get_string('editcategories', 'quiz'); 106 107 popup_form ('edit.php?'.$pageurl->get_query_string().'&category=', $catmenu, 'catmenu', $current, '', '', '', false, 'self', "<strong>$strcategory</strong>"); 108 109 echo '<form method="get" action="edit.php" id="displayoptions">'; 110 echo "<fieldset class='invisiblefieldset'>"; 111 echo $pageurl->hidden_params_out(array('recurse', 'showhidden', 'showquestiontext')); 112 question_category_form_checkbox('recurse', $recurse); 113 question_category_form_checkbox('showhidden', $showhidden); 114 question_category_form_checkbox('showquestiontext', $showquestiontext); 115 echo '<noscript><div class="centerpara"><input type="submit" value="'. get_string('go') .'" />'; 116 echo '</div></noscript></fieldset></form>'; 117 } 118 119 /** 120 * Private funciton to help the preceeding function. 121 */ 122 function question_category_form_checkbox($name, $checked) { 123 echo '<div><input type="hidden" id="' . $name . '_off" name="' . $name . '" value="0" />'; 124 echo '<input type="checkbox" id="' . $name . '_on" name="' . $name . '" value="1"'; 125 if ($checked) { 126 echo ' checked="checked"'; 127 } 128 echo ' onchange="getElementById(\'displayoptions\').submit(); return true;" />'; 129 echo '<label for="' . $name . '_on">'; 130 print_string($name, 'quiz'); 131 echo "</label></div>\n"; 132 } 133 134 /** 135 * Prints the table of questions in a category with interactions 136 * 137 * @param object $course The course object 138 * @param int $categoryid The id of the question category to be displayed 139 * @param int $cm The course module record if we are in the context of a particular module, 0 otherwise 140 * @param int $recurse This is 1 if subcategories should be included, 0 otherwise 141 * @param int $page The number of the page to be displayed 142 * @param int $perpage Number of questions to show per page 143 * @param boolean $showhidden True if also hidden questions should be displayed 144 * @param boolean $showquestiontext whether the text of each question should be shown in the list 145 */ 146 function question_list($contexts, $pageurl, $categoryandcontext, $cm = null, 147 $recurse=1, $page=0, $perpage=100, $showhidden=false, $sortorder='typename', $sortorderdecoded='qtype, name ASC', 148 $showquestiontext = false, $addcontexts = array()) { 149 global $USER, $CFG, $THEME, $COURSE; 150 151 list($categoryid, $contextid)= explode(',', $categoryandcontext); 152 153 $qtypemenu = question_type_menu(); 154 155 $strcategory = get_string("category", "quiz"); 156 $strquestion = get_string("question", "quiz"); 157 $straddquestions = get_string("addquestions", "quiz"); 158 $strimportquestions = get_string("importquestions", "quiz"); 159 $strexportquestions = get_string("exportquestions", "quiz"); 160 $strnoquestions = get_string("noquestions", "quiz"); 161 $strselect = get_string("select", "quiz"); 162 $strselectall = get_string("selectall", "quiz"); 163 $strselectnone = get_string("selectnone", "quiz"); 164 $strcreatenewquestion = get_string("createnewquestion", "quiz"); 165 $strquestionname = get_string("questionname", "quiz"); 166 $strdelete = get_string("delete"); 167 $stredit = get_string("edit"); 168 $strmove = get_string('moveqtoanothercontext', 'question'); 169 $strview = get_string("view"); 170 $straction = get_string("action"); 171 $strrestore = get_string('restore'); 172 173 $strtype = get_string("type", "quiz"); 174 $strcreatemultiple = get_string("createmultiple", "quiz"); 175 $strpreview = get_string("preview","quiz"); 176 177 if (!$categoryid) { 178 echo "<p style=\"text-align:center;\"><b>"; 179 print_string("selectcategoryabove", "quiz"); 180 echo "</b></p>"; 181 return; 182 } 183 184 if (!$category = get_record('question_categories', 'id', $categoryid, 'contextid', $contextid)) { 185 notify('Category not found!'); 186 return; 187 } 188 $catcontext = get_context_instance_by_id($contextid); 189 $canadd = has_capability('moodle/question:add', $catcontext); 190 //check for capabilities on all questions in category, will also apply to sub cats. 191 $caneditall =has_capability('moodle/question:editall', $catcontext); 192 $canuseall =has_capability('moodle/question:useall', $catcontext); 193 $canmoveall =has_capability('moodle/question:moveall', $catcontext); 194 195 if ($cm AND $cm->modname == 'quiz') { 196 $quizid = $cm->instance; 197 } else { 198 $quizid = 0; 199 } 200 $returnurl = $pageurl->out(); 201 $questionurl = new moodle_url("$CFG->wwwroot/question/question.php", 202 array('returnurl' => $returnurl)); 203 if ($cm!==null){ 204 $questionurl->param('cmid', $cm->id); 205 } else { 206 $questionurl->param('courseid', $COURSE->id); 207 } 208 $questionmoveurl = new moodle_url("$CFG->wwwroot/question/contextmoveq.php", 209 array('returnurl' => $returnurl)); 210 if ($cm!==null){ 211 $questionmoveurl->param('cmid', $cm->id); 212 } else { 213 $questionmoveurl->param('courseid', $COURSE->id); 214 } 215 echo '<div class="boxaligncenter">'; 216 $formatoptions = new stdClass; 217 $formatoptions->noclean = true; 218 echo format_text($category->info, FORMAT_MOODLE, $formatoptions, $COURSE->id); 219 220 echo '<table><tr>'; 221 222 if ($canadd) { 223 echo '<td valign="top" align="right">'; 224 popup_form ($questionurl->out(false, array('category' => $category->id)).'&qtype=', $qtypemenu, "addquestion", "", "choose", "", "", false, "self", "<strong>$strcreatenewquestion</strong>"); 225 echo '</td><td valign="top" align="right">'; 226 helpbutton("questiontypes", $strcreatenewquestion, "quiz"); 227 echo '</td>'; 228 } 229 else { 230 echo '<td>'; 231 print_string('nopermissionadd', 'question'); 232 echo '</td>'; 233 } 234 235 echo '</tr></table>'; 236 echo '</div>'; 237 238 $categorylist = ($recurse) ? question_categorylist($category->id) : $category->id; 239 240 // hide-feature 241 $showhidden = $showhidden ? '' : " AND hidden = '0'"; 242 243 if (!$totalnumber = count_records_select('question', "category IN ($categorylist) AND parent = '0' $showhidden")) { 244 echo "<p style=\"text-align:center;\">"; 245 print_string("noquestions", "quiz"); 246 echo "</p>"; 247 return; 248 } 249 250 if (!$questions = get_records_select('question', "category IN ($categorylist) AND parent = '0' $showhidden", $sortorderdecoded, '*', $page*$perpage, $perpage)) { 251 // There are no questions on the requested page. 252 $page = 0; 253 if (!$questions = get_records_select('question', "category IN ($categorylist) AND parent = '0' $showhidden", $sortorderdecoded, '*', 0, $perpage)) { 254 // There are no questions at all 255 echo "<p style=\"text-align:center;\">"; 256 print_string("noquestions", "quiz"); 257 echo "</p>"; 258 return; 259 } 260 } 261 262 print_paging_bar($totalnumber, $page, $perpage, $pageurl, 'qpage'); 263 264 echo question_sort_options($pageurl, $sortorder); 265 266 267 echo '<form method="post" action="edit.php">'; 268 echo '<fieldset class="invisiblefieldset" style="display: block;">'; 269 echo '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />'; 270 echo $pageurl->hidden_params_out(); 271 echo '<table id="categoryquestions" style="width: 100%"><tr>'; 272 echo "<th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">$straction</th>"; 273 274 echo "<th style=\"white-space:nowrap; text-align: left;\" class=\"header\" scope=\"col\">$strquestionname</th> 275 <th style=\"white-space:nowrap; text-align: right;\" class=\"header\" scope=\"col\">$strtype</th>"; 276 echo "</tr>\n"; 277 foreach ($questions as $question) { 278 $nameclass = ''; 279 $textclass = ''; 280 if ($question->hidden) { 281 $nameclass = 'dimmed_text'; 282 $textclass = 'dimmed_text'; 283 } 284 if ($showquestiontext) { 285 $nameclass .= ' header'; 286 } 287 if ($nameclass) { 288 $nameclass = 'class="' . $nameclass . '"'; 289 } 290 if ($textclass) { 291 $textclass = 'class="' . $textclass . '"'; 292 } 293 294 echo "<tr>\n<td style=\"white-space:nowrap;\" $nameclass>\n"; 295 296 $canuseq = question_has_capability_on($question, 'use', $question->category); 297 if (function_exists('module_specific_actions')) { 298 echo module_specific_actions($pageurl, $question->id, $cm->id, $canuseq); 299 } 300 301 // preview 302 if ($canuseq) { 303 $quizorcourseid = $quizid?('&quizid=' . $quizid):('&courseid=' .$COURSE->id); 304 link_to_popup_window('/question/preview.php?id=' . $question->id . $quizorcourseid, 'questionpreview', 305 "<img src=\"$CFG->pixpath/t/preview.gif\" class=\"iconsmall\" alt=\"$strpreview\" />", 306 0, 0, $strpreview, QUESTION_PREVIEW_POPUP_OPTIONS); 307 } 308 // edit, hide, delete question, using question capabilities, not quiz capabilieies 309 if (question_has_capability_on($question, 'edit', $question->category) || question_has_capability_on($question, 'move', $question->category)) { 310 echo "<a title=\"$stredit\" href=\"".$questionurl->out(false, array('id'=>$question->id))."\"><img 311 src=\"$CFG->pixpath/t/edit.gif\" alt=\"$stredit\" /></a> "; 312 } elseif (question_has_capability_on($question, 'view', $question->category)){ 313 echo "<a title=\"$strview\" href=\"".$questionurl->out(false, array('id'=>$question->id))."\"><img 314 src=\"$CFG->pixpath/i/info.gif\" alt=\"$strview\" /></a> "; 315 } 316 317 if (question_has_capability_on($question, 'move', $question->category) && question_has_capability_on($question, 'view', $question->category)) { 318 echo "<a title=\"$strmove\" href=\"".$questionurl->out(false, array('id'=>$question->id, 'movecontext'=>1))."\"><img 319 src=\"$CFG->pixpath/t/move.gif\" alt=\"$strmove\" /></a> "; 320 } 321 322 if (question_has_capability_on($question, 'edit', $question->category)) { 323 // hide-feature 324 if($question->hidden) { 325 echo "<a title=\"$strrestore\" href=\"edit.php?".$pageurl->get_query_string()."&unhide=$question->id&sesskey=$USER->sesskey\"><img 326 src=\"$CFG->pixpath/t/restore.gif\" alt=\"$strrestore\" /></a>"; 327 } else { 328 echo "<a title=\"$strdelete\" href=\"edit.php?".$pageurl->get_query_string()."&deleteselected=$question->id&q$question->id=1\"><img 329 src=\"$CFG->pixpath/t/delete.gif\" alt=\"$strdelete\" /></a>"; 330 } 331 } 332 if ($caneditall || $canmoveall || $canuseall){ 333 echo " <input title=\"$strselect\" type=\"checkbox\" name=\"q$question->id\" value=\"1\" />"; 334 } 335 echo "</td>\n"; 336 337 echo "<td $nameclass>" . format_string($question->name) . "</td>\n"; 338 echo "<td $nameclass style='text-align: right'>\n"; 339 print_question_icon($question); 340 echo "</td>\n"; 341 echo "</tr>\n"; 342 if($showquestiontext){ 343 echo '<tr><td colspan="3" ' . $textclass . '>'; 344 $formatoptions = new stdClass; 345 $formatoptions->noclean = true; 346 $formatoptions->para = false; 347 echo format_text($question->questiontext, $question->questiontextformat, 348 $formatoptions, $COURSE->id); 349 echo "</td></tr>\n"; 350 } 351 } 352 echo "</table>\n"; 353 354 $paging = print_paging_bar($totalnumber, $page, $perpage, $pageurl, 'qpage', false, true); 355 if ($totalnumber > DEFAULT_QUESTIONS_PER_PAGE) { 356 if ($perpage == DEFAULT_QUESTIONS_PER_PAGE) { 357 $showall = '<a href="edit.php?'.$pageurl->get_query_string(array('qperpage'=>1000)).'">'.get_string('showall', 'moodle', $totalnumber).'</a>'; 358 } else { 359 $showall = '<a href="edit.php?'.$pageurl->get_query_string(array('qperpage'=>DEFAULT_QUESTIONS_PER_PAGE)).'">'.get_string('showperpage', 'moodle', DEFAULT_QUESTIONS_PER_PAGE).'</a>'; 360 } 361 if ($paging) { 362 $paging = substr($paging, 0, strrpos($paging, '</div>')); 363 $paging .= "<br />$showall</div>"; 364 } else { 365 $paging = "<div class='paging'>$showall</div>"; 366 } 367 } 368 echo $paging; 369 370 if ($caneditall || $canmoveall || $canuseall){ 371 echo '<a href="javascript:select_all_in(\'TABLE\',null,\'categoryquestions\');">'.$strselectall.'</a> /'. 372 ' <a href="javascript:deselect_all_in(\'TABLE\',null,\'categoryquestions\');">'.$strselectnone.'</a>'; 373 echo '<br />'; 374 echo '<strong> '.get_string('withselected', 'quiz').':</strong><br />'; 375 376 if (function_exists('module_specific_buttons')) { 377 echo module_specific_buttons($cm->id); 378 } 379 // print delete and move selected question 380 if ($caneditall) { 381 echo '<input type="submit" name="deleteselected" value="'.$strdelete."\" />\n"; 382 } 383 if ($canmoveall && count($addcontexts)) { 384 echo '<input type="submit" name="move" value="'.get_string('moveto', 'quiz')."\" />\n"; 385 question_category_select_menu($addcontexts, false, 0, "$category->id,$category->contextid"); 386 } 387 388 if (function_exists('module_specific_controls') && $canuseall) { 389 echo module_specific_controls($totalnumber, $recurse, $category, $cm->id); 390 } 391 } 392 echo '</fieldset>'; 393 echo "</form>\n"; 394 } 395 function question_sort_options($pageurl, $sortorder){ 396 global $USER; 397 //sort options 398 $html = "<div class=\"mdl-align\">"; 399 $html .= '<form method="post" action="edit.php">'; 400 $html .= '<fieldset class="invisiblefieldset" style="display: block;">'; 401 $html .= '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />'; 402 $html .= $pageurl->hidden_params_out(array('qsortorder')); 403 $sortoptions = array('alpha' => get_string("sortalpha", "quiz"), 404 'typealpha' => get_string("sorttypealpha", "quiz"), 405 'age' => get_string("sortage", "quiz")); 406 $html .= choose_from_menu ($sortoptions, 'qsortorder', $sortorder, false, 'this.form.submit();', '0', true); 407 $html .= '<noscript><div><input type="submit" value="'.get_string("sortsubmit", "quiz").'" /></div></noscript>'; 408 $html .= '</fieldset>'; 409 $html .= "</form>\n"; 410 $html .= "</div>\n"; 411 return $html; 412 } 413 414 function question_showbank_actions($pageurl, $cm){ 415 global $CFG, $COURSE; 416 /// Now, check for commands on this page and modify variables as necessary 417 if (optional_param('move', false, PARAM_BOOL) and confirm_sesskey()) { /// Move selected questions to new category 418 $category = required_param('category', PARAM_SEQUENCE); 419 list($tocategoryid, $contextid) = explode(',', $category); 420 if (! $tocategory = get_record('question_categories', 'id', $tocategoryid, 'contextid', $contextid)) { 421 error('Could not find category record'); 422 } 423 $tocontext = get_context_instance_by_id($contextid); 424 require_capability('moodle/question:add', $tocontext); 425 $rawdata = (array) data_submitted(); 426 $questionids = array(); 427 foreach ($rawdata as $key => $value) { // Parse input for question ids 428 if (preg_match('!^q([0-9]+)$!', $key, $matches)) { 429 $key = $matches[1]; 430 $questionids[] = $key; 431 } 432 } 433 if ($questionids){ 434 $questionidlist = join($questionids, ','); 435 $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"; 436 if (!$questions = get_records_sql($sql)){ 437 print_error('questiondoesnotexist', 'question', $pageurl->out()); 438 } 439 $checkforfiles = false; 440 foreach ($questions as $question){ 441 //check capabilities 442 question_require_capability_on($question, 'move'); 443 $fromcontext = get_context_instance_by_id($question->contextid); 444 if (get_filesdir_from_context($fromcontext) != get_filesdir_from_context($tocontext)){ 445 $checkforfiles = true; 446 } 447 } 448 $returnurl = $pageurl->out(false, array('category'=>"$tocategoryid,$contextid")); 449 if (!$checkforfiles){ 450 if (!question_move_questions_to_category(implode(',', $questionids), $tocategory->id)) { 451 print_error('errormovingquestions', 'question', $returnurl, $questionids); 452 } 453 redirect($returnurl); 454 } else { 455 $movecontexturl = new moodle_url($CFG->wwwroot.'/question/contextmoveq.php', 456 array('returnurl' => $returnurl, 457 'ids'=>$questionidlist, 458 'tocatid'=> $tocategoryid)); 459 if ($cm){ 460 $movecontexturl->param('cmid', $cm->id); 461 } else { 462 $movecontexturl->param('courseid', $COURSE->id); 463 } 464 redirect($movecontexturl->out()); 465 } 466 } 467 } 468 469 if (optional_param('deleteselected', false, PARAM_BOOL)) { // delete selected questions from the category 470 if (($confirm = optional_param('confirm', '', PARAM_ALPHANUM)) and confirm_sesskey()) { // teacher has already confirmed the action 471 $deleteselected = required_param('deleteselected'); 472 if ($confirm == md5($deleteselected)) { 473 if ($questionlist = explode(',', $deleteselected)) { 474 // for each question either hide it if it is in use or delete it 475 foreach ($questionlist as $questionid) { 476 question_require_capability_on($questionid, 'edit'); 477 if (record_exists('quiz_question_instances', 'question', $questionid)) { 478 if (!set_field('question', 'hidden', 1, 'id', $questionid)) { 479 question_require_capability_on($questionid, 'edit'); 480 error('Was not able to hide question'); 481 } 482 } else { 483 delete_question($questionid); 484 } 485 } 486 } 487 redirect($pageurl->out()); 488 } else { 489 error("Confirmation string was incorrect"); 490 } 491 } 492 } 493 494 // Unhide a question 495 if(($unhide = optional_param('unhide', '', PARAM_INT)) and confirm_sesskey()) { 496 question_require_capability_on($unhide, 'edit'); 497 if(!set_field('question', 'hidden', 0, 'id', $unhide)) { 498 error("Failed to unhide the question."); 499 } 500 redirect($pageurl->out()); 501 } 502 } 503 504 /** 505 * Shows the question bank editing interface. 506 * 507 * The function also processes a number of actions: 508 * 509 * Actions affecting the question pool: 510 * move Moves a question to a different category 511 * deleteselected Deletes the selected questions from the category 512 * Other actions: 513 * category Chooses the category 514 * displayoptions Sets display options 515 * 516 * @author Martin Dougiamas and many others. This has recently been extensively 517 * rewritten by Gustav Delius and other members of the Serving Mathematics project 518 * {@link http://maths.york.ac.uk/serving_maths} 519 * @param moodle_url $pageurl object representing this pages url. 520 */ 521 function question_showbank($tabname, $contexts, $pageurl, $cm, $page, $perpage, $sortorder, $sortorderdecoded, $cat, $recurse, $showhidden, $showquestiontext){ 522 global $COURSE; 523 524 if (optional_param('deleteselected', false, PARAM_BOOL)){ // teacher still has to confirm 525 // make a list of all the questions that are selected 526 $rawquestions = $_REQUEST; // This code is called by both POST forms and GET links, so cannot use data_submitted. 527 $questionlist = ''; // comma separated list of ids of questions to be deleted 528 $questionnames = ''; // string with names of questions separated by <br /> with 529 // an asterix in front of those that are in use 530 $inuse = false; // set to true if at least one of the questions is in use 531 foreach ($rawquestions as $key => $value) { // Parse input for question ids 532 if (preg_match('!^q([0-9]+)$!', $key, $matches)) { 533 $key = $matches[1]; 534 $questionlist .= $key.','; 535 question_require_capability_on($key, 'edit'); 536 if (record_exists('quiz_question_instances', 'question', $key)) { 537 $questionnames .= '* '; 538 $inuse = true; 539 } 540 $questionnames .= get_field('question', 'name', 'id', $key).'<br />'; 541 } 542 } 543 if (!$questionlist) { // no questions were selected 544 redirect($pageurl->out()); 545 } 546 $questionlist = rtrim($questionlist, ','); 547 548 // Add an explanation about questions in use 549 if ($inuse) { 550 $questionnames .= '<br />'.get_string('questionsinuse', 'quiz'); 551 } 552 notice_yesno(get_string("deletequestionscheck", "quiz", $questionnames), 553 $pageurl->out_action(array('deleteselected'=>$questionlist, 'confirm'=>md5($questionlist))), 554 $pageurl->out_action()); 555 556 echo '</td></tr>'; 557 echo '</table>'; 558 print_footer($COURSE); 559 exit; 560 } 561 562 563 // starts with category selection form 564 print_box_start('generalbox questionbank'); 565 print_heading(get_string('questionbank', 'question'), '', 2); 566 question_category_form($contexts->having_one_edit_tab_cap($tabname), $pageurl, $cat, $recurse, $showhidden, $showquestiontext); 567 568 // continues with list of questions 569 question_list($contexts->having_one_edit_tab_cap($tabname), $pageurl, $cat, isset($cm) ? $cm : null, 570 $recurse, $page, $perpage, $showhidden, $sortorder, $sortorderdecoded, $showquestiontext, 571 $contexts->having_cap('moodle/question:add')); 572 573 print_box_end(); 574 } 575 /** 576 * Common setup for all pages for editing questions. 577 * @param string $edittab code for this edit tab 578 * @param boolean $requirecmid require cmid? default false 579 * @param boolean $requirecourseid require courseid, if cmid is not given? default true 580 * @return array $thispageurl, $contexts, $cmid, $cm, $module, $pagevars 581 */ 582 function question_edit_setup($edittab, $requirecmid = false, $requirecourseid = true){ 583 global $COURSE, $QUESTION_EDITTABCAPS; 584 585 //$thispageurl is used to construct urls for all question edit pages we link to from this page. It contains an array 586 //of parameters that are passed from page to page. 587 $thispageurl = new moodle_url(); 588 if ($requirecmid){ 589 $cmid =required_param('cmid', PARAM_INT); 590 } else { 591 $cmid = optional_param('cmid', 0, PARAM_INT); 592 } 593 if ($cmid){ 594 list($module, $cm) = get_module_from_cmid($cmid); 595 $courseid = $cm->course; 596 $thispageurl->params(compact('cmid')); 597 require_login($courseid, false, $cm); 598 $thiscontext = get_context_instance(CONTEXT_MODULE, $cmid); 599 } else { 600 $module = null; 601 $cm = null; 602 if ($requirecourseid){ 603 $courseid = required_param('courseid', PARAM_INT); 604 } else { 605 $courseid = optional_param('courseid', 0, PARAM_INT); 606 } 607 if ($courseid){ 608 $thispageurl->params(compact('courseid')); 609 require_login($courseid, false); 610 $thiscontext = get_context_instance(CONTEXT_COURSE, $courseid); 611 } else { 612 $thiscontext = null; 613 } 614 } 615 616 if ($thiscontext){ 617 $contexts = new question_edit_contexts($thiscontext); 618 $contexts->require_one_edit_tab_cap($edittab); 619 620 } else { 621 $contexts = null; 622 } 623 624 625 626 $pagevars['qpage'] = optional_param('qpage', -1, PARAM_INT); 627 628 //pass 'cat' from page to page and when 'category' comes from a drop down menu 629 //then we also reset the qpage so we go to page 1 of 630 //a new cat. 631 $pagevars['cat'] = optional_param('cat', 0, PARAM_SEQUENCE);// if empty will be set up later 632 if ($category = optional_param('category', 0, PARAM_SEQUENCE)){ 633 if ($pagevars['cat'] != $category){ // is this a move to a new category? 634 $pagevars['cat'] = $category; 635 $pagevars['qpage'] = 0; 636 } 637 } 638 if ($pagevars['cat']){ 639 $thispageurl->param('cat', $pagevars['cat']); 640 } 641 if ($pagevars['qpage'] > -1) { 642 $thispageurl->param('qpage', $pagevars['qpage']); 643 } else { 644 $pagevars['qpage'] = 0; 645 } 646 647 $pagevars['qperpage'] = optional_param('qperpage', -1, PARAM_INT); 648 if ($pagevars['qperpage'] > -1) { 649 $thispageurl->param('qperpage', $pagevars['qperpage']); 650 } else { 651 $pagevars['qperpage'] = DEFAULT_QUESTIONS_PER_PAGE; 652 } 653 654 $sortoptions = array('alpha' => 'name, qtype ASC', 655 'typealpha' => 'qtype, name ASC', 656 'age' => 'id ASC'); 657 658 if ($sortorder = optional_param('qsortorder', '', PARAM_ALPHA)) { 659 $pagevars['qsortorderdecoded'] = $sortoptions[$sortorder]; 660 $pagevars['qsortorder'] = $sortorder; 661 $thispageurl->param('qsortorder', $sortorder); 662 } else { 663 $pagevars['qsortorderdecoded'] = $sortoptions['typealpha']; 664 $pagevars['qsortorder'] = 'typealpha'; 665 } 666 667 $defaultcategory = question_make_default_categories($contexts->all()); 668 669 $contextlistarr = array(); 670 foreach ($contexts->having_one_edit_tab_cap($edittab) as $context){ 671 $contextlistarr[] = "'$context->id'"; 672 } 673 $contextlist = join($contextlistarr, ' ,'); 674 if (!empty($pagevars['cat'])){ 675 $catparts = explode(',', $pagevars['cat']); 676 if (!$catparts[0] || (FALSE !== array_search($catparts[1], $contextlistarr)) || !count_records_select("question_categories", "id = '".$catparts[0]."' AND contextid = $catparts[1]")) { 677 print_error('invalidcategory', 'quiz'); 678 } 679 } else { 680 $category = $defaultcategory; 681 $pagevars['cat'] = "$category->id,$category->contextid"; 682 } 683 684 if(($recurse = optional_param('recurse', -1, PARAM_BOOL)) != -1) { 685 $pagevars['recurse'] = $recurse; 686 $thispageurl->param('recurse', $recurse); 687 } else { 688 $pagevars['recurse'] = 1; 689 } 690 691 if(($showhidden = optional_param('showhidden', -1, PARAM_BOOL)) != -1) { 692 $pagevars['showhidden'] = $showhidden; 693 $thispageurl->param('showhidden', $showhidden); 694 } else { 695 $pagevars['showhidden'] = 0; 696 } 697 698 if(($showquestiontext = optional_param('showquestiontext', -1, PARAM_BOOL)) != -1) { 699 $pagevars['showquestiontext'] = $showquestiontext; 700 $thispageurl->param('showquestiontext', $showquestiontext); 701 } else { 702 $pagevars['showquestiontext'] = 0; 703 } 704 705 //category list page 706 $pagevars['cpage'] = optional_param('cpage', 1, PARAM_INT); 707 if ($pagevars['cpage'] != 1){ 708 $thispageurl->param('cpage', $pagevars['cpage']); 709 } 710 711 712 return array($thispageurl, $contexts, $cmid, $cm, $module, $pagevars); 713 } 714 class question_edit_contexts{ 715 var $allcontexts; 716 /** 717 * @param current context 718 */ 719 function question_edit_contexts($thiscontext){ 720 $pcontextids = get_parent_contexts($thiscontext); 721 $contexts = array($thiscontext); 722 foreach ($pcontextids as $pcontextid){ 723 $contexts[] = get_context_instance_by_id($pcontextid); 724 } 725 $this->allcontexts = $contexts; 726 } 727 /** 728 * @return array all parent contexts 729 */ 730 function all(){ 731 return $this->allcontexts; 732 } 733 /** 734 * @return object lowest context which must be either the module or course context 735 */ 736 function lowest(){ 737 return $this->allcontexts[0]; 738 } 739 /** 740 * @param string $cap capability 741 * @return array parent contexts having capability, zero based index 742 */ 743 function having_cap($cap){ 744 $contextswithcap = array(); 745 foreach ($this->allcontexts as $context){ 746 if (has_capability($cap, $context)){ 747 $contextswithcap[] = $context; 748 } 749 } 750 return $contextswithcap; 751 } 752 /** 753 * @param array $caps capabilities 754 * @return array parent contexts having at least one of $caps, zero based index 755 */ 756 function having_one_cap($caps){ 757 $contextswithacap = array(); 758 foreach ($this->allcontexts as $context){ 759 foreach ($caps as $cap){ 760 if (has_capability($cap, $context)){ 761 $contextswithacap[] = $context; 762 break; //done with caps loop 763 } 764 } 765 } 766 return $contextswithacap; 767 } 768 /** 769 * @param string $tabname edit tab name 770 * @return array parent contexts having at least one of $caps, zero based index 771 */ 772 function having_one_edit_tab_cap($tabname){ 773 global $QUESTION_EDITTABCAPS; 774 return $this->having_one_cap($QUESTION_EDITTABCAPS[$tabname]); 775 } 776 /** 777 * Has at least one parent context got the cap $cap? 778 * 779 * @param string $cap capability 780 * @return boolean 781 */ 782 function have_cap($cap){ 783 return (count($this->having_cap($cap))); 784 } 785 786 /** 787 * Has at least one parent context got one of the caps $caps? 788 * 789 * @param string $cap capability 790 * @return boolean 791 */ 792 function have_one_cap($caps){ 793 foreach ($caps as $cap){ 794 if ($this->have_cap($cap)){ 795 return true; 796 } 797 } 798 return false; 799 } 800 /** 801 * Has at least one parent context got one of the caps for actions on $tabname 802 * 803 * @param string $tabname edit tab name 804 * @return boolean 805 */ 806 function have_one_edit_tab_cap($tabname){ 807 global $QUESTION_EDITTABCAPS; 808 return $this->have_one_cap($QUESTION_EDITTABCAPS[$tabname]); 809 } 810 /** 811 * Throw error if at least one parent context hasn't got the cap $cap 812 * 813 * @param string $cap capability 814 */ 815 function require_cap($cap){ 816 if (!$this->have_cap($cap)){ 817 print_error('nopermissions', '', '', $cap); 818 } 819 } 820 /** 821 * Throw error if at least one parent context hasn't got one of the caps $caps 822 * 823 * @param array $cap capabilities 824 */ 825 function require_one_cap($caps){ 826 if (!$this->have_one_cap($caps)){ 827 $capsstring = join($caps, ', '); 828 print_error('nopermissions', '', '', $capsstring); 829 } 830 } 831 /** 832 * Throw error if at least one parent context hasn't got one of the caps $caps 833 * 834 * @param string $tabname edit tab name 835 */ 836 function require_one_edit_tab_cap($tabname){ 837 if (!$this->have_one_edit_tab_cap($tabname)){ 838 print_error('nopermissions', '', '', 'access question edit tab '.$tabname); 839 } 840 } 841 } 842 843 //capabilities for each page of edit tab. 844 //this determines which contexts' categories are available. At least one 845 //page is displayed if user has one of the capability on at least one context 846 $QUESTION_EDITTABCAPS = array( 847 'editq' => array('moodle/question:add', 848 'moodle/question:editmine', 849 'moodle/question:editall', 850 'moodle/question:viewmine', 851 'moodle/question:viewall', 852 'moodle/question:usemine', 853 'moodle/question:useall', 854 'moodle/question:movemine', 855 'moodle/question:moveall'), 856 'questions'=>array('moodle/question:add', 857 'moodle/question:editmine', 858 'moodle/question:editall', 859 'moodle/question:viewmine', 860 'moodle/question:viewall', 861 'moodle/question:movemine', 862 'moodle/question:moveall'), 863 'categories'=>array('moodle/question:managecategory'), 864 'import'=>array('moodle/question:add'), 865 'export'=>array('moodle/question:viewall', 'moodle/question:viewmine')); 866 867 868 869 /** 870 * Make sure user is logged in as required in this context. 871 */ 872 function require_login_in_context($contextorid = null){ 873 if (!is_object($contextorid)){ 874 $context = get_context_instance_by_id($contextorid); 875 } else { 876 $context = $contextorid; 877 } 878 if ($context && ($context->contextlevel == CONTEXT_COURSE)) { 879 require_login($context->instanceid); 880 } else if ($context && ($context->contextlevel == CONTEXT_MODULE)) { 881 if ($cm = get_record('course_modules','id',$context->instanceid)) { 882 if (!$course = get_record('course', 'id', $cm->course)) { 883 error('Incorrect course.'); 884 } 885 require_course_login($course, true, $cm); 886 887 } else { 888 error('Incorrect course module id.'); 889 } 890 } else if ($context && ($context->contextlevel == CONTEXT_SYSTEM)) { 891 if (!empty($CFG->forcelogin)) { 892 require_login(); 893 } 894 895 } else { 896 require_login(); 897 } 898 } 899 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jan 14 11:33:29 2009 | Cross-referenced by PHPXref 0.7 |