See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
1 <?php 2 3 // This file is part of Moodle - http://moodle.org/ 4 // 5 // Moodle is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // Moodle is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 17 18 /** 19 * Provides the interface for grading essay questions 20 * 21 * @package mod_lesson 22 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 **/ 25 26 require_once('../../config.php'); 27 require_once($CFG->dirroot.'/mod/lesson/locallib.php'); 28 require_once($CFG->dirroot.'/mod/lesson/pagetypes/essay.php'); 29 require_once($CFG->dirroot.'/mod/lesson/essay_form.php'); 30 31 $id = required_param('id', PARAM_INT); // Course Module ID 32 $mode = optional_param('mode', 'display', PARAM_ALPHA); 33 34 $cm = get_coursemodule_from_id('lesson', $id, 0, false, MUST_EXIST); 35 $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); 36 $dblesson = $DB->get_record('lesson', array('id' => $cm->instance), '*', MUST_EXIST); 37 $lesson = new lesson($dblesson); 38 39 require_login($course, false, $cm); 40 $context = context_module::instance($cm->id); 41 require_capability('mod/lesson:grade', $context); 42 43 $url = new moodle_url('/mod/lesson/essay.php', array('id'=>$id)); 44 if ($mode !== 'display') { 45 $url->param('mode', $mode); 46 } 47 $PAGE->set_url($url); 48 $PAGE->set_secondary_active_tab('modulepage'); 49 50 $currentgroup = groups_get_activity_group($cm, true); 51 52 $attempt = new stdClass(); 53 $user = new stdClass(); 54 $attemptid = optional_param('attemptid', 0, PARAM_INT); 55 56 $formattextdefoptions = new stdClass(); 57 $formattextdefoptions->noclean = true; 58 $formattextdefoptions->para = false; 59 $formattextdefoptions->context = $context; 60 61 if ($attemptid > 0) { 62 $attempt = $DB->get_record('lesson_attempts', array('id' => $attemptid)); 63 $answer = $DB->get_record('lesson_answers', array('lessonid' => $lesson->id, 'pageid' => $attempt->pageid)); 64 $user = $DB->get_record('user', array('id' => $attempt->userid)); 65 // Apply overrides. 66 $lesson->update_effective_access($user->id); 67 $scoreoptions = array(); 68 if ($lesson->custom) { 69 $i = $answer->score; 70 while ($i >= 0) { 71 $scoreoptions[$i] = (string)$i; 72 $i--; 73 } 74 } else { 75 $scoreoptions[0] = get_string('nocredit', 'lesson'); 76 $scoreoptions[1] = get_string('credit', 'lesson'); 77 } 78 } 79 80 /// Handle any preprocessing before header is printed - based on $mode 81 switch ($mode) { 82 case 'grade': 83 // Grading form - get the necessary data 84 require_sesskey(); 85 86 if (empty($attempt)) { 87 throw new \moodle_exception('cannotfindattempt', 'lesson'); 88 } 89 if (empty($user)) { 90 throw new \moodle_exception('cannotfinduser', 'lesson'); 91 } 92 if (empty($answer)) { 93 throw new \moodle_exception('cannotfindanswer', 'lesson'); 94 } 95 break; 96 97 case 'update': 98 require_sesskey(); 99 100 if (empty($attempt)) { 101 throw new \moodle_exception('cannotfindattempt', 'lesson'); 102 } 103 if (empty($user)) { 104 throw new \moodle_exception('cannotfinduser', 'lesson'); 105 } 106 107 $editoroptions = array('noclean' => true, 'maxfiles' => EDITOR_UNLIMITED_FILES, 108 'maxbytes' => $CFG->maxbytes, 'context' => $context); 109 $essayinfo = lesson_page_type_essay::extract_useranswer($attempt->useranswer); 110 $essayinfo = file_prepare_standard_editor($essayinfo, 'response', $editoroptions, $context, 111 'mod_lesson', 'essay_responses', $attempt->id); 112 $mform = new essay_grading_form(null, array('scoreoptions' => $scoreoptions, 'user' => $user)); 113 $mform->set_data($essayinfo); 114 if ($mform->is_cancelled()) { 115 redirect("$CFG->wwwroot/mod/lesson/essay.php?id=$cm->id"); 116 } 117 if ($form = $mform->get_data()) { 118 if (!$grades = $DB->get_records('lesson_grades', array("lessonid"=>$lesson->id, "userid"=>$attempt->userid), 'completed', '*', $attempt->retry, 1)) { 119 throw new \moodle_exception('cannotfindgrade', 'lesson'); 120 } 121 122 $essayinfo->graded = 1; 123 $essayinfo->score = $form->score; 124 $form = file_postupdate_standard_editor($form, 'response', $editoroptions, $context, 125 'mod_lesson', 'essay_responses', $attempt->id); 126 $essayinfo->response = $form->response; 127 $essayinfo->responseformat = $form->responseformat; 128 $essayinfo->sent = 0; 129 if (!$lesson->custom && $essayinfo->score == 1) { 130 $attempt->correct = 1; 131 } else { 132 $attempt->correct = 0; 133 } 134 135 $attempt->useranswer = serialize($essayinfo); 136 137 $DB->update_record('lesson_attempts', $attempt); 138 139 // Get grade information 140 $grade = current($grades); 141 $gradeinfo = lesson_grade($lesson, $attempt->retry, $attempt->userid); 142 143 // Set and update 144 $updategrade = new stdClass(); 145 $updategrade->id = $grade->id; 146 $updategrade->grade = $gradeinfo->grade; 147 $DB->update_record('lesson_grades', $updategrade); 148 149 $params = array( 150 'context' => $context, 151 'objectid' => $grade->id, 152 'courseid' => $course->id, 153 'relateduserid' => $attempt->userid, 154 'other' => array( 155 'lessonid' => $lesson->id, 156 'attemptid' => $attemptid 157 ) 158 ); 159 $event = \mod_lesson\event\essay_assessed::create($params); 160 $event->add_record_snapshot('lesson', $dblesson); 161 $event->trigger(); 162 163 $lesson->add_message(get_string('changessaved'), 'notifysuccess'); 164 165 // update central gradebook 166 lesson_update_grades($lesson, $grade->userid); 167 168 redirect(new moodle_url('/mod/lesson/essay.php', array('id'=>$cm->id))); 169 } else { 170 throw new \moodle_exception('invalidformdata'); 171 } 172 break; 173 case 'email': 174 // Sending an email(s) to a single user or all 175 require_sesskey(); 176 177 // Get our users (could be singular) 178 if ($userid = optional_param('userid', 0, PARAM_INT)) { 179 $queryadd = " AND userid = ?"; 180 if (! $users = $DB->get_records('user', array('id' => $userid))) { 181 throw new \moodle_exception('cannotfinduser', 'lesson'); 182 } 183 } else { 184 $queryadd = ''; 185 186 // If group selected, only send to group members. 187 list($esql, $params) = get_enrolled_sql($context, '', $currentgroup, true); 188 list($sort, $sortparams) = users_order_by_sql('u'); 189 $params['lessonid'] = $lesson->id; 190 191 // Need to use inner view to avoid distinct + text 192 if (!$users = $DB->get_records_sql(" 193 SELECT u.* 194 FROM {user} u 195 JOIN ( 196 SELECT DISTINCT userid 197 FROM {lesson_attempts} 198 WHERE lessonid = :lessonid 199 ) ui ON u.id = ui.userid 200 JOIN ($esql) ue ON ue.id = u.id 201 ORDER BY $sort", $params)) { 202 throw new \moodle_exception('cannotfinduser', 'lesson'); 203 } 204 } 205 206 $pages = $lesson->load_all_pages(); 207 foreach ($pages as $key=>$page) { 208 if ($page->qtype != LESSON_PAGE_ESSAY) { 209 unset($pages[$key]); 210 } 211 } 212 213 // Get only the attempts that are in response to essay questions 214 list($usql, $params) = $DB->get_in_or_equal(array_keys($pages)); 215 if (!empty($queryadd)) { 216 $params[] = $userid; 217 } 218 if (!$attempts = $DB->get_records_select('lesson_attempts', "pageid $usql".$queryadd, $params)) { 219 throw new \moodle_exception('nooneansweredthisquestion', 'lesson'); 220 } 221 // Get the answers 222 list($answerUsql, $parameters) = $DB->get_in_or_equal(array_keys($pages)); 223 array_unshift($parameters, $lesson->id); 224 if (!$answers = $DB->get_records_select('lesson_answers', "lessonid = ? AND pageid $answerUsql", $parameters, '', 'pageid, score')) { 225 throw new \moodle_exception('cannotfindanswer', 'lesson'); 226 } 227 228 $userpicture = new user_picture($USER); 229 $userpicture->size = 1; // Use f1 size. 230 foreach ($attempts as $attempt) { 231 $essayinfo = lesson_page_type_essay::extract_useranswer($attempt->useranswer); 232 if ($essayinfo->graded && !$essayinfo->sent) { 233 // Holds values for the essayemailsubject string for the email message 234 $a = new stdClass; 235 236 // Set the grade 237 $grades = $DB->get_records('lesson_grades', array("lessonid"=>$lesson->id, "userid"=>$attempt->userid), 'completed', '*', $attempt->retry, 1); 238 $grade = current($grades); 239 $a->newgrade = $grade->grade; 240 241 // Set the points 242 if ($lesson->custom) { 243 $a->earned = $essayinfo->score; 244 $a->outof = $answers[$attempt->pageid]->score; 245 } else { 246 $a->earned = $essayinfo->score; 247 $a->outof = 1; 248 } 249 250 // Set rest of the message values 251 $currentpage = $lesson->load_page($attempt->pageid); 252 $a->question = format_text($currentpage->contents, $currentpage->contentsformat, $formattextdefoptions); 253 $answer = file_rewrite_pluginfile_urls($essayinfo->answer, 'pluginfile.php', $context->id, 254 'mod_lesson', 'essay_answers', $attempt->id); 255 $a->response = format_text($answer, $essayinfo->answerformat, 256 array('context' => $context, 'para' => true)); 257 $a->comment = $essayinfo->response; 258 $a->comment = file_rewrite_pluginfile_urls($a->comment, 'pluginfile.php', $context->id, 259 'mod_lesson', 'essay_responses', $attempt->id); 260 $a->comment = format_text($a->comment, $essayinfo->responseformat, $formattextdefoptions); 261 $a->lesson = format_string($lesson->name, true); 262 263 // Fetch message HTML and plain text formats 264 $message = get_string('essayemailmessage2', 'lesson', $a); 265 $plaintext = format_text_email($message, FORMAT_HTML); 266 267 $smallmessage = get_string('essayemailmessagesmall', 'lesson', $a); 268 $smallmessage = format_text_email($smallmessage, FORMAT_HTML); 269 270 // Subject 271 $subject = get_string('essayemailsubject', 'lesson'); 272 273 // Context url. 274 $contexturl = new moodle_url('/grade/report/user/index.php', array('id' => $course->id)); 275 276 $eventdata = new \core\message\message(); 277 $eventdata->courseid = $course->id; 278 $eventdata->modulename = 'lesson'; 279 $eventdata->userfrom = $USER; 280 $eventdata->userto = $users[$attempt->userid]; 281 $eventdata->subject = $subject; 282 $eventdata->fullmessage = $plaintext; 283 $eventdata->fullmessageformat = FORMAT_PLAIN; 284 $eventdata->fullmessagehtml = $message; 285 $eventdata->smallmessage = $smallmessage; 286 $eventdata->contexturl = $contexturl->out(false); 287 $userpicture->includetoken = $attempt->userid; // Generate an out-of-session token for the destinatary. 288 $eventdata->customdata = [ 289 'cmid' => $cm->id, 290 'instance' => $lesson->id, 291 'retake' => $lesson->id, 292 'notificationiconurl' => $userpicture->get_url($PAGE)->out(false), 293 ]; 294 295 // Required for messaging framework 296 $eventdata->component = 'mod_lesson'; 297 $eventdata->name = 'graded_essay'; 298 299 message_send($eventdata); 300 $essayinfo->sent = 1; 301 $attempt->useranswer = serialize($essayinfo); 302 $DB->update_record('lesson_attempts', $attempt); 303 } 304 } 305 $lesson->add_message(get_string('emailsuccess', 'lesson'), 'notifysuccess'); 306 redirect(new moodle_url('/mod/lesson/essay.php', array('id'=>$cm->id))); 307 break; 308 case 'display': // Default view - get the necessary data 309 default: 310 // Get lesson pages that are essay 311 $pages = $lesson->load_all_pages(); 312 foreach ($pages as $key=>$page) { 313 if ($page->qtype != LESSON_PAGE_ESSAY) { 314 unset($pages[$key]); 315 } 316 } 317 if (count($pages) > 0) { 318 // Get only the attempts that are in response to essay questions 319 list($usql, $parameters) = $DB->get_in_or_equal(array_keys($pages), SQL_PARAMS_NAMED); 320 // If group selected, only get group members attempts. 321 list($esql, $params) = get_enrolled_sql($context, '', $currentgroup, true); 322 $parameters = array_merge($params, $parameters); 323 324 $sql = "SELECT a.* 325 FROM {lesson_attempts} a 326 JOIN ($esql) ue ON a.userid = ue.id 327 WHERE pageid $usql"; 328 if ($essayattempts = $DB->get_records_sql($sql, $parameters)) { 329 $userfieldsapi = \core_user\fields::for_userpic(); 330 $ufields = $userfieldsapi->get_sql('u', false, '', '', false)->selects; 331 // Get all the users who have taken this lesson. 332 list($sort, $sortparams) = users_order_by_sql('u'); 333 334 $params['lessonid'] = $lesson->id; 335 $sql = "SELECT DISTINCT $ufields 336 FROM {user} u 337 JOIN {lesson_attempts} a ON u.id = a.userid 338 JOIN ($esql) ue ON ue.id = a.userid 339 WHERE a.lessonid = :lessonid 340 ORDER BY $sort"; 341 if (!$users = $DB->get_records_sql($sql, $params)) { 342 $mode = 'none'; // not displaying anything 343 if (!empty($currentgroup)) { 344 $groupname = groups_get_group_name($currentgroup); 345 $lesson->add_message(get_string('noonehasansweredgroup', 'lesson', $groupname)); 346 } else { 347 $lesson->add_message(get_string('noonehasanswered', 'lesson')); 348 } 349 } 350 } else { 351 $mode = 'none'; // not displaying anything 352 if (!empty($currentgroup)) { 353 $groupname = groups_get_group_name($currentgroup); 354 $lesson->add_message(get_string('noonehasansweredgroup', 'lesson', $groupname)); 355 } else { 356 $lesson->add_message(get_string('noonehasanswered', 'lesson')); 357 } 358 } 359 } else { 360 $mode = 'none'; // not displaying anything 361 $lesson->add_message(get_string('noessayquestionsfound', 'lesson')); 362 } 363 break; 364 } 365 366 $lessonoutput = $PAGE->get_renderer('mod_lesson'); 367 echo $lessonoutput->header($lesson, $cm, 'essay', false, null, get_string('manualgrading', 'lesson')); 368 369 switch ($mode) { 370 case 'display': 371 groups_print_activity_menu($cm, $url); 372 // Expects $user, $essayattempts and $pages to be set already 373 374 // Group all the essays by userid 375 $studentessays = array(); 376 foreach ($essayattempts as $essay) { 377 // Not very nice :) but basically 378 // this organizes the essays so we know how many 379 // times a student answered an essay per try and per page 380 $studentessays[$essay->userid][$essay->pageid][$essay->retry][] = $essay; 381 } 382 383 // Setup table 384 $table = new html_table(); 385 $table->head = array(get_string('name'), get_string('essays', 'lesson'), get_string('status'), 386 get_string('email', 'lesson')); 387 $table->attributes['class'] = 'standardtable generaltable'; 388 $table->align = array('left', 'left', 'left'); 389 $table->wrap = array('nowrap', 'nowrap', ''); 390 391 // Cycle through all the students 392 foreach (array_keys($studentessays) as $userid) { 393 $studentname = fullname($users[$userid], true); 394 $essaylinks = array(); 395 $essaystatuses = array(); 396 397 // Number of attempts on the lesson 398 $attempts = $lesson->count_user_retries($userid); 399 400 // Go through each essay page 401 foreach ($studentessays[$userid] as $page => $tries) { 402 $count = 0; 403 404 // Go through each attempt per page 405 foreach($tries as $try) { 406 if ($count == $attempts) { 407 break; // Stop displaying essays (attempt not completed) 408 } 409 $count++; 410 411 // Make sure they didn't answer it more than the max number of attempts. 412 $essay = $lesson->get_last_attempt($try); 413 414 // Start processing the attempt 415 $essayinfo = lesson_page_type_essay::extract_useranswer($essay->useranswer); 416 417 // link for each essay 418 $url = new moodle_url('/mod/lesson/essay.php', array('id'=>$cm->id,'mode'=>'grade','attemptid'=>$essay->id,'sesskey'=>sesskey())); 419 $linktitle = userdate($essay->timeseen, get_string('strftimedatetime')).' '. 420 format_string($pages[$essay->pageid]->title, true); 421 422 // Different colors for all the states of an essay (graded, if sent, not graded) 423 if (!$essayinfo->graded) { 424 $class = "badge badge-warning"; 425 $status = get_string('notgraded', 'lesson'); 426 } elseif (!$essayinfo->sent) { 427 $class = "badge badge-success"; 428 $status = get_string('graded', 'lesson'); 429 } else { 430 $class = "badge badge-success"; 431 $status = get_string('sent', 'lesson'); 432 } 433 $attributes = array('tabindex' => 0); 434 435 $essaylinks[] = html_writer::link($url, $linktitle); 436 $essaystatuses[] = html_writer::span($status, $class, $attributes); 437 } 438 } 439 // email link for this user 440 $url = new moodle_url('/mod/lesson/essay.php', array('id'=>$cm->id,'mode'=>'email','userid'=>$userid,'sesskey'=>sesskey())); 441 $emaillink = html_writer::link($url, get_string('emailgradedessays', 'lesson')); 442 443 $table->data[] = array($OUTPUT->user_picture($users[$userid], array('courseid' => $course->id)) . $studentname, 444 implode("<br />", $essaylinks), implode("<br />", $essaystatuses), $emaillink); 445 } 446 447 // email link for all users 448 $url = new moodle_url('/mod/lesson/essay.php', array('id'=>$cm->id,'mode'=>'email','sesskey'=>sesskey())); 449 $emailalllink = html_writer::link($url, get_string('emailallgradedessays', 'lesson')); 450 451 $table->data[] = array(' ', ' ', ' ', $emailalllink); 452 453 echo html_writer::table($table); 454 break; 455 case 'grade': 456 // Trigger the essay grade viewed event. 457 $event = \mod_lesson\event\essay_attempt_viewed::create(array( 458 'objectid' => $attempt->id, 459 'relateduserid' => $attempt->userid, 460 'context' => $context, 461 'courseid' => $course->id, 462 )); 463 $event->add_record_snapshot('lesson_attempts', $attempt); 464 $event->trigger(); 465 466 // Grading form 467 // Expects the following to be set: $attemptid, $answer, $user, $page, $attempt 468 $essayinfo = lesson_page_type_essay::extract_useranswer($attempt->useranswer); 469 $answer = file_rewrite_pluginfile_urls($essayinfo->answer, 'pluginfile.php', $context->id, 470 'mod_lesson', 'essay_answers', $attempt->id); 471 $currentpage = $lesson->load_page($attempt->pageid); 472 473 $mform = new essay_grading_form(null, array('scoreoptions'=>$scoreoptions, 'user'=>$user)); 474 $data = new stdClass; 475 $data->id = $cm->id; 476 $data->attemptid = $attemptid; 477 $data->score = $essayinfo->score; 478 $data->question = format_text($currentpage->contents, $currentpage->contentsformat, $formattextdefoptions); 479 $data->studentanswer = format_text($answer, $essayinfo->answerformat, 480 array('context' => $context, 'para' => true)); 481 $data->response = $essayinfo->response; 482 $data->responseformat = $essayinfo->responseformat; 483 $editoroptions = array('noclean' => true, 'maxfiles' => EDITOR_UNLIMITED_FILES, 484 'maxbytes' => $CFG->maxbytes, 'context' => $context); 485 $data = file_prepare_standard_editor($data, 'response', $editoroptions, $context, 486 'mod_lesson', 'essay_responses', $attempt->id); 487 $mform->set_data($data); 488 489 $mform->display(); 490 break; 491 default: 492 groups_print_activity_menu($cm, $url); 493 break; 494 } 495 496 echo $OUTPUT->footer();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body