65
* Gets the default category in a course
67
* It returns the first category with no parent category. If no categories
68
* exist yet then one is created.
69
* @return object The default category
70
* @param integer $courseid The id of the course whose default category is wanted
72
function get_default_question_category($courseid) {
73
// If it already exists, just return it.
74
if ($category = get_records_select("question_categories", "course = '$courseid' AND parent = '0'", 'id', '*', '', 1)) {
75
return reset($category);
78
// Otherwise, we need to make one
79
$category = new stdClass;
80
$category->name = get_string("default", "quiz");
81
$category->info = get_string("defaultinfo", "quiz");
82
$category->course = $courseid;
83
$category->parent = 0;
84
$category->sortorder = 999; // By default, all categories get this number, and are sorted alphabetically.
85
$category->publish = 0;
86
$category->stamp = make_unique_id_code();
88
if (!$category->id = insert_record("question_categories", $category)) {
89
notify("Error creating a default category!");
80
* @param integer $categoryid a category id.
81
* @return boolean whether this is the only top-level category in a context.
83
function question_is_only_toplevel_category_in_context($categoryid) {
85
return 1 == count_records_sql("
87
FROM {$CFG->prefix}question_categories c1,
88
{$CFG->prefix}question_categories c2
89
WHERE c2.id = $categoryid
90
AND c1.contextid = c2.contextid
91
AND c1.parent = 0 AND c2.parent = 0");
95
* Check whether this user is allowed to delete this category.
97
* @param integer $todelete a category id.
99
function question_can_delete_cat($todelete) {
100
if (question_is_only_toplevel_category_in_context($todelete)) {
101
error('You can\'t delete that category it is the default category for this context.');
103
$contextid = get_field('question_categories', 'contextid', 'id', $todelete);
104
require_capability('moodle/question:managecategory', get_context_instance_by_id($contextid));
96
108
* prints a form to choose categories
98
function question_category_form($course, $current, $recurse=1, $showhidden=false, $showquestiontext=false) {
110
function question_category_form($contexts, $pageurl, $current, $recurse=1, $showhidden=false, $showquestiontext=false) {
101
/// Make sure the default category exists for this course
102
get_default_question_category($course->id);
104
114
/// Get all the existing categories now
105
$catmenu = question_category_options($course->id, true);
107
$strcategory = get_string("category", "quiz");
108
$strshow = get_string("show", "quiz");
109
$streditcats = get_string("editcategories", "quiz");
111
echo "<table><tr><td style=\"white-space:nowrap;\">";
112
echo "<strong>$strcategory:</strong> ";
114
popup_form ("edit.php?courseid=$course->id&cat=", $catmenu, "catmenu", $current, "", "", "", false, "self");
115
echo "</td><td align=\"right\">";
116
echo "<form method=\"get\" action=\"$CFG->wwwroot/question/category.php\">";
118
echo "<input type=\"hidden\" name=\"id\" value=\"$course->id\" />";
119
echo "<input type=\"submit\" value=\"$streditcats\" />";
122
echo '</td></tr></table>';
115
$catmenu = question_category_options($contexts, false, 0, true);
117
$strcategory = get_string('category', 'quiz');
118
$strshow = get_string('show', 'quiz');
119
$streditcats = get_string('editcategories', 'quiz');
121
popup_form ('edit.php?'.$pageurl->get_query_string().'&category=', $catmenu, 'catmenu', $current, '', '', '', false, 'self', "<strong>$strcategory</strong>");
124
123
echo '<form method="get" action="edit.php" id="displayoptions">';
125
124
echo "<fieldset class='invisiblefieldset'>";
126
echo "<input type=\"hidden\" name=\"courseid\" value=\"{$course->id}\" />\n";
125
echo $pageurl->hidden_params_out(array('recurse', 'showhidden', 'showquestiontext'));
127
126
question_category_form_checkbox('recurse', $recurse);
128
127
question_category_form_checkbox('showhidden', $showhidden);
129
128
question_category_form_checkbox('showquestiontext', $showquestiontext);
339
359
$formatoptions->noclean = true;
340
360
$formatoptions->para = false;
341
361
echo format_text($question->questiontext, $question->questiontextformat,
342
$formatoptions, $course->id);
362
$formatoptions, $COURSE->id);
343
363
echo "</td></tr>\n";
346
366
echo "</table>\n";
348
$paging = print_paging_bar($totalnumber, $page, $perpage,
349
"edit.php?courseid={$course->id}&perpage=$perpage&", 'page',
368
$paging = print_paging_bar($totalnumber, $page, $perpage, $pageurl, 'qpage', false, true);
351
369
if ($totalnumber > DEFAULT_QUESTIONS_PER_PAGE) {
352
370
if ($perpage == DEFAULT_QUESTIONS_PER_PAGE) {
353
$showall = '<a href="edit.php?courseid='.$course->id.'&perpage=1000">'.get_string('showall', 'moodle', $totalnumber).'</a>';
371
$showall = '<a href="edit.php?'.$pageurl->get_query_string(array('qperpage'=>1000)).'">'.get_string('showall', 'moodle', $totalnumber).'</a>';
355
$showall = '<a href="edit.php?courseid='.$course->id.'&perpage=' . DEFAULT_QUESTIONS_PER_PAGE . '">'.get_string('showperpage', 'moodle', DEFAULT_QUESTIONS_PER_PAGE).'</a>';
373
$showall = '<a href="edit.php?'.$pageurl->get_query_string(array('qperpage'=>DEFAULT_QUESTIONS_PER_PAGE)).'">'.get_string('showperpage', 'moodle', DEFAULT_QUESTIONS_PER_PAGE).'</a>';
358
376
$paging = substr($paging, 0, strrpos($paging, '</div>'));
359
377
$paging .= "<br />$showall</div>";
361
$paging = "<div class='paging'>$showall</div>";
379
$paging = "<div class='paging'>$showall</div>";
366
echo '<table class="quiz-edit-selected"><tr><td colspan="2">';
367
echo '<a href="javascript:select_all_in(\'TABLE\', null, \'categoryquestions\');">'.$strselectall.'</a> /'.
368
' <a href="javascript:deselect_all_in(\'TABLE\', null, \'categoryquestions\');">'.$strselectnone.'</a>'.
369
'</td><td align="right"><b> '.get_string('withselected', 'quiz').':</b></td></tr><tr><td>';
372
echo "<input type=\"submit\" name=\"add\" value=\"{$THEME->larrow} $straddtoquiz\" />\n";
375
// print delete and move selected question
377
echo '<input type="submit" name="deleteselected" value="'.$strdelete."\" /></td><td>\n";
378
echo '<input type="submit" name="move" value="'.get_string('moveto', 'quiz')."\" />\n";
379
question_category_select_menu($course->id, false, true, $category->id);
381
echo "</td></tr></table>";
383
// add random question
385
for ($i = 1;$i <= min(10, $totalnumber); $i++) {
386
$randomcount[$i] = $i;
388
for ($i = 20;$i <= min(100, $totalnumber); $i += 10) {
389
$randomcount[$i] = $i;
384
if ($caneditall || $canmoveall || $canuseall){
385
echo '<a href="javascript:select_all_in(\'TABLE\',null,\'categoryquestions\');">'.$strselectall.'</a> /'.
386
' <a href="javascript:deselect_all_in(\'TABLE\',null,\'categoryquestions\');">'.$strselectnone.'</a>';
392
print_string('addrandom', 'quiz',
393
choose_from_menu($randomcount, 'randomcount', '1', '', '', '', true));
394
echo '<input type="hidden" name="recurse" value="'.$recurse.'" />';
395
echo "<input type=\"hidden\" name=\"categoryid\" value=\"$category->id\" />";
396
echo ' <input type="submit" name="addrandom" value="'. get_string('add') .'" />';
397
helpbutton('random', get_string('random', 'quiz'), 'quiz');
388
echo '<strong> '.get_string('withselected', 'quiz').':</strong><br />';
390
if (function_exists('module_specific_buttons')) {
391
echo module_specific_buttons($cm->id);
393
// print delete and move selected question
395
echo '<input type="submit" name="deleteselected" value="'.$strdelete."\" />\n";
397
if ($canmoveall && count($addcontexts)) {
398
echo '<input type="submit" name="move" value="'.get_string('moveto', 'quiz')."\" />\n";
399
question_category_select_menu($addcontexts, false, 0, "$category->id,$category->contextid");
402
if (function_exists('module_specific_controls') && $canuseall) {
403
echo module_specific_controls($totalnumber, $recurse, $category, $cm->id);
399
406
echo '</fieldset>';
400
407
echo "</form>\n";
b'\\ No newline at end of file'
409
function question_sort_options($pageurl, $sortorder){
412
$html = "<div class=\"mdl-align\">";
413
$html .= '<form method="post" action="edit.php">';
414
$html .= '<fieldset class="invisiblefieldset" style="display: block;">';
415
$html .= '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
416
$html .= $pageurl->hidden_params_out(array('qsortorder'));
417
$sortoptions = array('alpha' => get_string("sortalpha", "quiz"),
418
'typealpha' => get_string("sorttypealpha", "quiz"),
419
'age' => get_string("sortage", "quiz"));
420
$html .= choose_from_menu ($sortoptions, 'qsortorder', $sortorder, false, 'this.form.submit();', '0', true);
421
$html .= '<noscript><div><input type="submit" value="'.get_string("sortsubmit", "quiz").'" /></div></noscript>';
422
$html .= '</fieldset>';
423
$html .= "</form>\n";
428
function question_showbank_actions($pageurl, $cm){
429
global $CFG, $COURSE;
430
/// Now, check for commands on this page and modify variables as necessary
431
if (optional_param('move', false, PARAM_BOOL) and confirm_sesskey()) { /// Move selected questions to new category
432
$category = required_param('category', PARAM_SEQUENCE);
433
list($tocategoryid, $contextid) = explode(',', $category);
434
if (! $tocategory = get_record('question_categories', 'id', $tocategoryid, 'contextid', $contextid)) {
435
error('Could not find category record');
437
$tocontext = get_context_instance_by_id($contextid);
438
require_capability('moodle/question:add', $tocontext);
439
$rawdata = (array) data_submitted();
440
$questionids = array();
441
foreach ($rawdata as $key => $value) { // Parse input for question ids
442
if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
444
$questionids[] = $key;
448
$questionidlist = join($questionids, ',');
449
$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";
450
if (!$questions = get_records_sql($sql)){
451
print_error('questiondoesnotexist', 'question', $pageurl->out());
453
$checkforfiles = false;
454
foreach ($questions as $question){
456
question_require_capability_on($question, 'move');
457
$fromcontext = get_context_instance_by_id($question->contextid);
458
if (get_filesdir_from_context($fromcontext) != get_filesdir_from_context($tocontext)){
459
$checkforfiles = true;
462
$returnurl = $pageurl->out(false, array('category'=>"$tocategoryid,$contextid"));
463
if (!$checkforfiles){
464
if (!question_move_questions_to_category(implode(',', $questionids), $tocategory->id)) {
465
print_error('errormovingquestions', 'question', $returnurl, $questionids);
467
redirect($returnurl);
469
$movecontexturl = new moodle_url($CFG->wwwroot.'/question/contextmoveq.php',
470
array('returnurl' => $returnurl,
471
'ids'=>$questionidlist,
472
'tocatid'=> $tocategoryid));
474
$movecontexturl->param('cmid', $cm->id);
476
$movecontexturl->param('courseid', $COURSE->id);
478
redirect($movecontexturl->out());
483
if (optional_param('deleteselected', false, PARAM_BOOL)) { // delete selected questions from the category
484
if (($confirm = optional_param('confirm', '', PARAM_ALPHANUM)) and confirm_sesskey()) { // teacher has already confirmed the action
485
$deleteselected = required_param('deleteselected');
486
if ($confirm == md5($deleteselected)) {
487
if ($questionlist = explode(',', $deleteselected)) {
488
// for each question either hide it if it is in use or delete it
489
foreach ($questionlist as $questionid) {
490
question_require_capability_on($questionid, 'edit');
491
if (record_exists('quiz_question_instances', 'question', $questionid)) {
492
if (!set_field('question', 'hidden', 1, 'id', $questionid)) {
493
question_require_capability_on($questionid, 'edit');
494
error('Was not able to hide question');
497
delete_question($questionid);
501
redirect($pageurl->out());
503
error("Confirmation string was incorrect");
509
if(($unhide = optional_param('unhide', '', PARAM_INT)) and confirm_sesskey()) {
510
question_require_capability_on($unhide, 'edit');
511
if(!set_field('question', 'hidden', 0, 'id', $unhide)) {
512
error("Failed to unhide the question.");
514
redirect($pageurl->out());
519
* Shows the question bank editing interface.
521
* The function also processes a number of actions:
523
* Actions affecting the question pool:
524
* move Moves a question to a different category
525
* deleteselected Deletes the selected questions from the category
527
* category Chooses the category
528
* displayoptions Sets display options
530
* @author Martin Dougiamas and many others. This has recently been extensively
531
* rewritten by Gustav Delius and other members of the Serving Mathematics project
532
* {@link http://maths.york.ac.uk/serving_maths}
533
* @param moodle_url $pageurl object representing this pages url.
535
function question_showbank($tabname, $contexts, $pageurl, $cm, $page, $perpage, $sortorder, $sortorderdecoded, $cat, $recurse, $showhidden, $showquestiontext){
538
if (optional_param('deleteselected', false, PARAM_BOOL)){ // teacher still has to confirm
539
// make a list of all the questions that are selected
540
$rawquestions = $_REQUEST; // This code is called by both POST forms and GET links, so cannot use data_submitted.
541
$questionlist = ''; // comma separated list of ids of questions to be deleted
542
$questionnames = ''; // string with names of questions separated by <br /> with
543
// an asterix in front of those that are in use
544
$inuse = false; // set to true if at least one of the questions is in use
545
foreach ($rawquestions as $key => $value) { // Parse input for question ids
546
if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
548
$questionlist .= $key.',';
549
question_require_capability_on($key, 'edit');
550
if (record_exists('quiz_question_instances', 'question', $key)) {
551
$questionnames .= '* ';
554
$questionnames .= get_field('question', 'name', 'id', $key).'<br />';
557
if (!$questionlist) { // no questions were selected
558
redirect($pageurl->out());
560
$questionlist = rtrim($questionlist, ',');
562
// Add an explanation about questions in use
564
$questionnames .= '<br />'.get_string('questionsinuse', 'quiz');
566
notice_yesno(get_string("deletequestionscheck", "quiz", $questionnames),
567
$pageurl->out_action(array('deleteselected'=>$questionlist, 'confirm'=>md5($questionlist))),
568
$pageurl->out_action());
572
print_footer($COURSE);
577
// starts with category selection form
578
print_box_start('generalbox questionbank');
579
print_heading(get_string('questionbank', 'question'), '', 2);
580
question_category_form($contexts->having_one_edit_tab_cap($tabname), $pageurl, $cat, $recurse, $showhidden, $showquestiontext);
582
// continues with list of questions
583
question_list($contexts->having_one_edit_tab_cap($tabname), $pageurl, $cat, isset($cm) ? $cm : null,
584
$recurse, $page, $perpage, $showhidden, $sortorder, $sortorderdecoded, $showquestiontext,
585
$contexts->having_cap('moodle/question:add'));
590
* Common setup for all pages for editing questions.
591
* @param string $edittab code for this edit tab
592
* @param boolean $requirecmid require cmid? default false
593
* @param boolean $requirecourseid require courseid, if cmid is not given? default true
594
* @return array $thispageurl, $contexts, $cmid, $cm, $module, $pagevars
596
function question_edit_setup($edittab, $requirecmid = false, $requirecourseid = true){
597
global $COURSE, $QUESTION_EDITTABCAPS;
599
//$thispageurl is used to construct urls for all question edit pages we link to from this page. It contains an array
600
//of parameters that are passed from page to page.
601
$thispageurl = new moodle_url();
603
$cmid =required_param('cmid', PARAM_INT);
605
$cmid = optional_param('cmid', 0, PARAM_INT);
608
list($module, $cm) = get_module_from_cmid($cmid);
609
$courseid = $cm->course;
610
$thispageurl->params(compact('cmid'));
611
require_login($courseid, false, $cm);
612
$thiscontext = get_context_instance(CONTEXT_MODULE, $cmid);
616
if ($requirecourseid){
617
$courseid = required_param('courseid', PARAM_INT);
619
$courseid = optional_param('courseid', 0, PARAM_INT);
622
$thispageurl->params(compact('courseid'));
623
require_login($courseid, false);
624
$thiscontext = get_context_instance(CONTEXT_COURSE, $courseid);
631
$contexts = new question_edit_contexts($thiscontext);
632
$contexts->require_one_edit_tab_cap($edittab);
640
$pagevars['qpage'] = optional_param('qpage', -1, PARAM_INT);
642
//pass 'cat' from page to page and when 'category' comes from a drop down menu
643
//then we also reset the qpage so we go to page 1 of
645
$pagevars['cat'] = optional_param('cat', 0, PARAM_SEQUENCE);// if empty will be set up later
646
if ($category = optional_param('category', 0, PARAM_SEQUENCE)){
647
if ($pagevars['cat'] != $category){ // is this a move to a new category?
648
$pagevars['cat'] = $category;
649
$pagevars['qpage'] = 0;
652
if ($pagevars['cat']){
653
$thispageurl->param('cat', $pagevars['cat']);
655
if ($pagevars['qpage'] > -1) {
656
$thispageurl->param('qpage', $pagevars['qpage']);
658
$pagevars['qpage'] = 0;
661
$pagevars['qperpage'] = optional_param('qperpage', -1, PARAM_INT);
662
if ($pagevars['qperpage'] > -1) {
663
$thispageurl->param('qperpage', $pagevars['qperpage']);
665
$pagevars['qperpage'] = DEFAULT_QUESTIONS_PER_PAGE;
668
$sortoptions = array('alpha' => 'name, qtype ASC',
669
'typealpha' => 'qtype, name ASC',
672
if ($sortorder = optional_param('qsortorder', '', PARAM_ALPHA)) {
673
$pagevars['qsortorderdecoded'] = $sortoptions[$sortorder];
674
$pagevars['qsortorder'] = $sortorder;
675
$thispageurl->param('qsortorder', $sortorder);
677
$pagevars['qsortorderdecoded'] = $sortoptions['typealpha'];
678
$pagevars['qsortorder'] = 'typealpha';
681
$defaultcategory = question_make_default_categories($contexts->all());
683
$contextlistarr = array();
684
foreach ($contexts->having_one_edit_tab_cap($edittab) as $context){
685
$contextlistarr[] = "'$context->id'";
687
$contextlist = join($contextlistarr, ' ,');
688
if (!empty($pagevars['cat'])){
689
$catparts = explode(',', $pagevars['cat']);
690
if (!$catparts[0] || (FALSE !== array_search($catparts[1], $contextlistarr)) || !count_records_select("question_categories", "id = '".$catparts[0]."' AND contextid = $catparts[1]")) {
691
print_error('invalidcategory', 'quiz');
694
$category = $defaultcategory;
695
$pagevars['cat'] = "$category->id,$category->contextid";
698
if(($recurse = optional_param('recurse', -1, PARAM_BOOL)) != -1) {
699
$pagevars['recurse'] = $recurse;
700
$thispageurl->param('recurse', $recurse);
702
$pagevars['recurse'] = 1;
705
if(($showhidden = optional_param('showhidden', -1, PARAM_BOOL)) != -1) {
706
$pagevars['showhidden'] = $showhidden;
707
$thispageurl->param('showhidden', $showhidden);
709
$pagevars['showhidden'] = 0;
712
if(($showquestiontext = optional_param('showquestiontext', -1, PARAM_BOOL)) != -1) {
713
$pagevars['showquestiontext'] = $showquestiontext;
714
$thispageurl->param('showquestiontext', $showquestiontext);
716
$pagevars['showquestiontext'] = 0;
720
$pagevars['cpage'] = optional_param('cpage', 1, PARAM_INT);
721
if ($pagevars['cpage'] < 1) {
722
$pagevars['cpage'] = 1;
724
if ($pagevars['cpage'] != 1){
725
$thispageurl->param('cpage', $pagevars['cpage']);
729
return array($thispageurl, $contexts, $cmid, $cm, $module, $pagevars);
731
class question_edit_contexts{
734
* @param current context
736
function question_edit_contexts($thiscontext){
737
$pcontextids = get_parent_contexts($thiscontext);
738
$contexts = array($thiscontext);
739
foreach ($pcontextids as $pcontextid){
740
$contexts[] = get_context_instance_by_id($pcontextid);
742
$this->allcontexts = $contexts;
745
* @return array all parent contexts
748
return $this->allcontexts;
751
* @return object lowest context which must be either the module or course context
754
return $this->allcontexts[0];
757
* @param string $cap capability
758
* @return array parent contexts having capability, zero based index
760
function having_cap($cap){
761
$contextswithcap = array();
762
foreach ($this->allcontexts as $context){
763
if (has_capability($cap, $context)){
764
$contextswithcap[] = $context;
767
return $contextswithcap;
770
* @param array $caps capabilities
771
* @return array parent contexts having at least one of $caps, zero based index
773
function having_one_cap($caps){
774
$contextswithacap = array();
775
foreach ($this->allcontexts as $context){
776
foreach ($caps as $cap){
777
if (has_capability($cap, $context)){
778
$contextswithacap[] = $context;
779
break; //done with caps loop
783
return $contextswithacap;
786
* @param string $tabname edit tab name
787
* @return array parent contexts having at least one of $caps, zero based index
789
function having_one_edit_tab_cap($tabname){
790
global $QUESTION_EDITTABCAPS;
791
return $this->having_one_cap($QUESTION_EDITTABCAPS[$tabname]);
794
* Has at least one parent context got the cap $cap?
796
* @param string $cap capability
799
function have_cap($cap){
800
return (count($this->having_cap($cap)));
804
* Has at least one parent context got one of the caps $caps?
806
* @param string $cap capability
809
function have_one_cap($caps){
810
foreach ($caps as $cap){
811
if ($this->have_cap($cap)){
818
* Has at least one parent context got one of the caps for actions on $tabname
820
* @param string $tabname edit tab name
823
function have_one_edit_tab_cap($tabname){
824
global $QUESTION_EDITTABCAPS;
825
return $this->have_one_cap($QUESTION_EDITTABCAPS[$tabname]);
828
* Throw error if at least one parent context hasn't got the cap $cap
830
* @param string $cap capability
832
function require_cap($cap){
833
if (!$this->have_cap($cap)){
834
print_error('nopermissions', '', '', $cap);
838
* Throw error if at least one parent context hasn't got one of the caps $caps
840
* @param array $cap capabilities
842
function require_one_cap($caps){
843
if (!$this->have_one_cap($caps)){
844
$capsstring = join($caps, ', ');
845
print_error('nopermissions', '', '', $capsstring);
849
* Throw error if at least one parent context hasn't got one of the caps $caps
851
* @param string $tabname edit tab name
853
function require_one_edit_tab_cap($tabname){
854
if (!$this->have_one_edit_tab_cap($tabname)){
855
print_error('nopermissions', '', '', 'access question edit tab '.$tabname);
860
//capabilities for each page of edit tab.
861
//this determines which contexts' categories are available. At least one
862
//page is displayed if user has one of the capability on at least one context
863
$QUESTION_EDITTABCAPS = array(
864
'editq' => array('moodle/question:add',
865
'moodle/question:editmine',
866
'moodle/question:editall',
867
'moodle/question:viewmine',
868
'moodle/question:viewall',
869
'moodle/question:usemine',
870
'moodle/question:useall',
871
'moodle/question:movemine',
872
'moodle/question:moveall'),
873
'questions'=>array('moodle/question:add',
874
'moodle/question:editmine',
875
'moodle/question:editall',
876
'moodle/question:viewmine',
877
'moodle/question:viewall',
878
'moodle/question:movemine',
879
'moodle/question:moveall'),
880
'categories'=>array('moodle/question:managecategory'),
881
'import'=>array('moodle/question:add'),
882
'export'=>array('moodle/question:viewall', 'moodle/question:viewmine'));
887
* Make sure user is logged in as required in this context.
889
function require_login_in_context($contextorid = null){
890
if (!is_object($contextorid)){
891
$context = get_context_instance_by_id($contextorid);
893
$context = $contextorid;
895
if ($context && ($context->contextlevel == CONTEXT_COURSE)) {
896
require_login($context->instanceid);
897
} else if ($context && ($context->contextlevel == CONTEXT_MODULE)) {
898
if ($cm = get_record('course_modules','id',$context->instanceid)) {
899
if (!$course = get_record('course', 'id', $cm->course)) {
900
error('Incorrect course.');
902
require_course_login($course, true, $cm);
905
error('Incorrect course module id.');
907
} else if ($context && ($context->contextlevel == CONTEXT_SYSTEM)) {
908
if (!empty($CFG->forcelogin)) {