[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * This file contains the ingest manager for the assignfeedback_editpdf plugin 19 * 20 * @package assignfeedback_editpdf 21 * @copyright 2012 Davo Smith 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace assignfeedback_editpdf; 26 27 /** 28 * Functions for generating the annotated pdf. 29 * 30 * This class controls the ingest of student submission files to a normalised 31 * PDF 1.4 document with all submission files concatinated together. It also 32 * provides the functions to generate a downloadable pdf with all comments and 33 * annotations embedded. 34 * @copyright 2012 Davo Smith 35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 36 */ 37 class document_services { 38 39 /** File area for generated pdf */ 40 const FINAL_PDF_FILEAREA = 'download'; 41 /** File area for combined pdf */ 42 const COMBINED_PDF_FILEAREA = 'combined'; 43 /** File area for page images */ 44 const PAGE_IMAGE_FILEAREA = 'pages'; 45 /** File area for readonly page images */ 46 const PAGE_IMAGE_READONLY_FILEAREA = 'readonlypages'; 47 /** Filename for combined pdf */ 48 const COMBINED_PDF_FILENAME = 'combined.pdf'; 49 50 /** 51 * This function will take an int or an assignment instance and 52 * return an assignment instance. It is just for convenience. 53 * @param int|\assign $assignment 54 * @return assign 55 */ 56 private static function get_assignment_from_param($assignment) { 57 global $CFG; 58 59 require_once($CFG->dirroot . '/mod/assign/locallib.php'); 60 61 if (!is_object($assignment)) { 62 $cm = \get_coursemodule_from_instance('assign', $assignment, 0, false, MUST_EXIST); 63 $context = \context_module::instance($cm->id); 64 65 $assignment = new \assign($context, null, null); 66 } 67 return $assignment; 68 } 69 70 /** 71 * Get a hash that will be unique and can be used in a path name. 72 * @param int|\assign $assignment 73 * @param int $userid 74 * @param int $attemptnumber (-1 means latest attempt) 75 */ 76 private static function hash($assignment, $userid, $attemptnumber) { 77 if (is_object($assignment)) { 78 $assignmentid = $assignment->get_instance()->id; 79 } else { 80 $assignmentid = $assignment; 81 } 82 return sha1($assignmentid . '_' . $userid . '_' . $attemptnumber); 83 } 84 85 /** 86 * This function will search for all files that can be converted 87 * and concatinated into a PDF (1.4) - for any submission plugin 88 * for this students attempt. 89 * @param int|\assign $assignment 90 * @param int $userid 91 * @param int $attemptnumber (-1 means latest attempt) 92 * @return array(stored_file) 93 */ 94 public static function list_compatible_submission_files_for_attempt($assignment, $userid, $attemptnumber) { 95 global $USER, $DB; 96 97 $assignment = self::get_assignment_from_param($assignment); 98 99 // Capability checks. 100 if (!$assignment->can_view_submission($userid)) { 101 \print_error('nopermission'); 102 } 103 104 $files = array(); 105 106 if ($assignment->get_instance()->teamsubmission) { 107 $submission = $assignment->get_group_submission($userid, 0, false); 108 } else { 109 $submission = $assignment->get_user_submission($userid, false); 110 } 111 $user = $DB->get_record('user', array('id' => $userid)); 112 113 // User has not submitted anything yet. 114 if (!$submission) { 115 return $files; 116 } 117 // Ask each plugin for it's list of files. 118 foreach ($assignment->get_submission_plugins() as $plugin) { 119 if ($plugin->is_enabled() && $plugin->is_visible()) { 120 $pluginfiles = $plugin->get_files($submission, $user); 121 foreach ($pluginfiles as $filename => $file) { 122 if (($file instanceof \stored_file) && ($file->get_mimetype() === 'application/pdf')) { 123 $files[$filename] = $file; 124 } 125 } 126 } 127 } 128 return $files; 129 } 130 131 /** 132 * This function return the combined pdf for all valid submission files. 133 * @param int|\assign $assignment 134 * @param int $userid 135 * @param int $attemptnumber (-1 means latest attempt) 136 * @return stored_file 137 */ 138 public static function get_combined_pdf_for_attempt($assignment, $userid, $attemptnumber) { 139 140 global $USER, $DB; 141 142 $assignment = self::get_assignment_from_param($assignment); 143 144 // Capability checks. 145 if (!$assignment->can_view_submission($userid)) { 146 \print_error('nopermission'); 147 } 148 149 $grade = $assignment->get_user_grade($userid, true, $attemptnumber); 150 if ($assignment->get_instance()->teamsubmission) { 151 $submission = $assignment->get_group_submission($userid, 0, false); 152 } else { 153 $submission = $assignment->get_user_submission($userid, false); 154 } 155 156 $contextid = $assignment->get_context()->id; 157 $component = 'assignfeedback_editpdf'; 158 $filearea = self::COMBINED_PDF_FILEAREA; 159 $itemid = $grade->id; 160 $filepath = '/'; 161 $filename = self::COMBINED_PDF_FILENAME; 162 $fs = \get_file_storage(); 163 164 $combinedpdf = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename); 165 if (!$combinedpdf || 166 ($submission && ($combinedpdf->get_timemodified() < $submission->timemodified))) { 167 return self::generate_combined_pdf_for_attempt($assignment, $userid, $attemptnumber); 168 } 169 return $combinedpdf; 170 } 171 172 /** 173 * This function will take all of the compatible files for a submission 174 * and combine them into one PDF. 175 * @param int|\assign $assignment 176 * @param int $userid 177 * @param int $attemptnumber (-1 means latest attempt) 178 * @return stored_file 179 */ 180 public static function generate_combined_pdf_for_attempt($assignment, $userid, $attemptnumber) { 181 global $CFG; 182 183 require_once($CFG->libdir . '/pdflib.php'); 184 185 $assignment = self::get_assignment_from_param($assignment); 186 187 if (!$assignment->can_view_submission($userid)) { 188 \print_error('nopermission'); 189 } 190 191 $files = self::list_compatible_submission_files_for_attempt($assignment, $userid, $attemptnumber); 192 193 $pdf = new pdf(); 194 if (!$files) { 195 // No valid submission files - create an empty pdf. 196 $pdf->AddPage(); 197 } else { 198 199 // Create a mega joined PDF. 200 $compatiblepdfs = array(); 201 foreach ($files as $file) { 202 $compatiblepdf = pdf::ensure_pdf_compatible($file); 203 if ($compatiblepdf) { 204 array_push($compatiblepdfs, $compatiblepdf); 205 } 206 } 207 208 $tmpdir = \make_temp_directory('assignfeedback_editpdf/combined/' . self::hash($assignment, $userid, $attemptnumber)); 209 $tmpfile = $tmpdir . '/' . self::COMBINED_PDF_FILENAME; 210 211 @unlink($tmpfile); 212 try { 213 $pagecount = $pdf->combine_pdfs($compatiblepdfs, $tmpfile); 214 } catch (\Exception $e) { 215 debugging('TCPDF could not process the pdf files:' . $e->getMessage(), DEBUG_DEVELOPER); 216 // TCPDF does not recover from errors so we need to re-initialise the class. 217 $pagecount = 0; 218 } 219 if ($pagecount == 0) { 220 // We at least want a single blank page. 221 debugging('TCPDF did not produce a valid pdf:' . $tmpfile . '. Replacing with a blank pdf.', DEBUG_DEVELOPER); 222 $pdf = new pdf(); 223 $pdf->AddPage(); 224 @unlink($tmpfile); 225 $files = false; 226 } 227 } 228 229 $grade = $assignment->get_user_grade($userid, true, $attemptnumber); 230 $record = new \stdClass(); 231 232 $record->contextid = $assignment->get_context()->id; 233 $record->component = 'assignfeedback_editpdf'; 234 $record->filearea = self::COMBINED_PDF_FILEAREA; 235 $record->itemid = $grade->id; 236 $record->filepath = '/'; 237 $record->filename = self::COMBINED_PDF_FILENAME; 238 $fs = \get_file_storage(); 239 240 $fs->delete_area_files($record->contextid, $record->component, $record->filearea, $record->itemid); 241 242 // Detect corrupt generated pdfs and replace with a blank one. 243 if ($files) { 244 $pagecount = $pdf->load_pdf($tmpfile); 245 if ($pagecount <= 0) { 246 $files = false; 247 } 248 } 249 250 if (!$files) { 251 // This was a blank pdf. 252 unset($pdf); 253 $pdf = new pdf(); 254 $content = $pdf->Output(self::COMBINED_PDF_FILENAME, 'S'); 255 $file = $fs->create_file_from_string($record, $content); 256 } else { 257 // This was a combined pdf. 258 $file = $fs->create_file_from_pathname($record, $tmpfile); 259 @unlink($tmpfile); 260 261 // Test the generated file for correctness. 262 $compatiblepdf = pdf::ensure_pdf_compatible($file); 263 } 264 265 return $file; 266 } 267 268 /** 269 * This function will return the number of pages of a pdf. 270 * @param int|\assign $assignment 271 * @param int $userid 272 * @param int $attemptnumber (-1 means latest attempt) 273 * @param bool $readonly When true we get the number of pages for the readonly version. 274 * @return int number of pages 275 */ 276 public static function page_number_for_attempt($assignment, $userid, $attemptnumber, $readonly = false) { 277 global $CFG; 278 279 require_once($CFG->libdir . '/pdflib.php'); 280 281 $assignment = self::get_assignment_from_param($assignment); 282 283 if (!$assignment->can_view_submission($userid)) { 284 \print_error('nopermission'); 285 } 286 287 // When in readonly we can return the number of images in the DB because they should already exist, 288 // if for some reason they do not, then we proceed as for the normal version. 289 if ($readonly) { 290 $grade = $assignment->get_user_grade($userid, true, $attemptnumber); 291 $fs = get_file_storage(); 292 $files = $fs->get_directory_files($assignment->get_context()->id, 'assignfeedback_editpdf', 293 self::PAGE_IMAGE_READONLY_FILEAREA, $grade->id, '/'); 294 $pagecount = count($files); 295 if ($pagecount > 0) { 296 return $pagecount; 297 } 298 } 299 300 // Get a combined pdf file from all submitted pdf files. 301 $file = self::get_combined_pdf_for_attempt($assignment, $userid, $attemptnumber); 302 if (!$file) { 303 \print_error('Could not generate combined pdf.'); 304 } 305 306 // Store the combined pdf file somewhere to be opened by tcpdf. 307 $tmpdir = \make_temp_directory('assignfeedback_editpdf/pagetotal/' 308 . self::hash($assignment, $userid, $attemptnumber)); 309 $combined = $tmpdir . '/' . self::COMBINED_PDF_FILENAME; 310 $file->copy_content_to($combined); // Copy the file. 311 312 // Get the total number of pages. 313 $pdf = new pdf(); 314 $pagecount = $pdf->set_pdf($combined); 315 316 // Delete temporary folders and files. 317 @unlink($combined); 318 @rmdir($tmpdir); 319 320 return $pagecount; 321 } 322 323 /** 324 * This function will generate and return a list of the page images from a pdf. 325 * @param int|\assign $assignment 326 * @param int $userid 327 * @param int $attemptnumber (-1 means latest attempt) 328 * @return array(stored_file) 329 */ 330 public static function generate_page_images_for_attempt($assignment, $userid, $attemptnumber) { 331 global $CFG; 332 333 require_once($CFG->libdir . '/pdflib.php'); 334 335 $assignment = self::get_assignment_from_param($assignment); 336 337 if (!$assignment->can_view_submission($userid)) { 338 \print_error('nopermission'); 339 } 340 341 // Need to generate the page images - first get a combined pdf. 342 $file = self::get_combined_pdf_for_attempt($assignment, $userid, $attemptnumber); 343 if (!$file) { 344 throw new \moodle_exception('Could not generate combined pdf.'); 345 } 346 347 $tmpdir = \make_temp_directory('assignfeedback_editpdf/pageimages/' . self::hash($assignment, $userid, $attemptnumber)); 348 $combined = $tmpdir . '/' . self::COMBINED_PDF_FILENAME; 349 $file->copy_content_to($combined); // Copy the file. 350 351 $pdf = new pdf(); 352 353 $pdf->set_image_folder($tmpdir); 354 $pagecount = $pdf->set_pdf($combined); 355 356 $grade = $assignment->get_user_grade($userid, true, $attemptnumber); 357 358 $record = new \stdClass(); 359 $record->contextid = $assignment->get_context()->id; 360 $record->component = 'assignfeedback_editpdf'; 361 $record->filearea = self::PAGE_IMAGE_FILEAREA; 362 $record->itemid = $grade->id; 363 $record->filepath = '/'; 364 $fs = \get_file_storage(); 365 366 $files = array(); 367 for ($i = 0; $i < $pagecount; $i++) { 368 $image = $pdf->get_image($i); 369 $record->filename = basename($image); 370 $files[$i] = $fs->create_file_from_pathname($record, $tmpdir . '/' . $image); 371 @unlink($tmpdir . '/' . $image); 372 } 373 374 @unlink($combined); 375 @rmdir($tmpdir); 376 377 return $files; 378 } 379 380 /** 381 * This function returns a list of the page images from a pdf. 382 * 383 * The readonly version is different than the normal one. The readonly version contains a copy 384 * of the pages in the state they were when the PDF was annotated, by doing so we prevent the 385 * the pages that are displayed to change as soon as the submission changes. 386 * 387 * Though there is an edge case, if the PDF was annotated before MDL-45580, then it is possible 388 * that we do not find any readonly version of the pages. In that case, we will get the normal 389 * pages and copy them to the readonly area. This ensures that the pages will remain in that 390 * state until the submission is updated. When the normal files do not exist, we throw an exception 391 * because the readonly pages should only ever be displayed after a teacher has annotated the PDF, 392 * they would not exist until they do. 393 * 394 * @param int|\assign $assignment 395 * @param int $userid 396 * @param int $attemptnumber (-1 means latest attempt) 397 * @param bool $readonly If true, then we are requesting the readonly version. 398 * @return array(stored_file) 399 */ 400 public static function get_page_images_for_attempt($assignment, $userid, $attemptnumber, $readonly = false) { 401 402 $assignment = self::get_assignment_from_param($assignment); 403 404 if (!$assignment->can_view_submission($userid)) { 405 \print_error('nopermission'); 406 } 407 408 if ($assignment->get_instance()->teamsubmission) { 409 $submission = $assignment->get_group_submission($userid, 0, false); 410 } else { 411 $submission = $assignment->get_user_submission($userid, false); 412 } 413 $grade = $assignment->get_user_grade($userid, true, $attemptnumber); 414 415 $contextid = $assignment->get_context()->id; 416 $component = 'assignfeedback_editpdf'; 417 $itemid = $grade->id; 418 $filepath = '/'; 419 $filearea = self::PAGE_IMAGE_FILEAREA; 420 421 $fs = \get_file_storage(); 422 423 // If we are after the readonly pages... 424 $copytoreadonly = false; 425 if ($readonly) { 426 $filearea = self::PAGE_IMAGE_READONLY_FILEAREA; 427 if ($fs->is_area_empty($contextid, $component, $filearea, $itemid)) { 428 // We have a problem here, we were supposed to find the files... 429 // let's fallback on the other area, and copy the files to the readonly area. 430 $copytoreadonly = true; 431 $filearea = self::PAGE_IMAGE_FILEAREA; 432 } 433 } 434 435 $files = $fs->get_directory_files($contextid, $component, $filearea, $itemid, $filepath); 436 437 $pages = array(); 438 if (!empty($files)) { 439 $first = reset($files); 440 if (!$readonly && $first->get_timemodified() < $submission->timemodified) { 441 // Image files are stale, we need to regenerate them, except in readonly mode. 442 // We also need to remove the draft annotations and comments associated with this attempt. 443 $fs->delete_area_files($contextid, $component, $filearea, $itemid); 444 page_editor::delete_draft_content($itemid); 445 $files = array(); 446 } else { 447 448 // Need to reorder the files following their name. 449 // because get_directory_files() return a different order than generate_page_images_for_attempt(). 450 foreach($files as $file) { 451 // Extract the page number from the file name image_pageXXXX.png. 452 preg_match('/page([\d]+)\./', $file->get_filename(), $matches); 453 if (empty($matches) or !is_numeric($matches[1])) { 454 throw new \coding_exception("'" . $file->get_filename() 455 . "' file hasn't the expected format filename: image_pageXXXX.png."); 456 } 457 $pagenumber = (int)$matches[1]; 458 459 // Save the page in the ordered array. 460 $pages[$pagenumber] = $file; 461 } 462 ksort($pages); 463 464 if ($copytoreadonly) { 465 self::copy_pages_to_readonly_area($assignment, $grade); 466 } 467 } 468 } 469 470 if (empty($pages)) { 471 if ($readonly) { 472 // This should never happen, there should be a version of the pages available 473 // whenever we are requesting the readonly version. 474 throw new \moodle_exception('Could not find readonly pages for grade ' . $grade->id); 475 } 476 $pages = self::generate_page_images_for_attempt($assignment, $userid, $attemptnumber); 477 } 478 479 return $pages; 480 } 481 482 /** 483 * This function returns sensible filename for a feedback file. 484 * @param int|\assign $assignment 485 * @param int $userid 486 * @param int $attemptnumber (-1 means latest attempt) 487 * @return string 488 */ 489 protected static function get_downloadable_feedback_filename($assignment, $userid, $attemptnumber) { 490 global $DB; 491 492 $assignment = self::get_assignment_from_param($assignment); 493 494 $groupmode = groups_get_activity_groupmode($assignment->get_course_module()); 495 $groupname = ''; 496 if ($groupmode) { 497 $groupid = groups_get_activity_group($assignment->get_course_module(), true); 498 $groupname = groups_get_group_name($groupid).'-'; 499 } 500 if ($groupname == '-') { 501 $groupname = ''; 502 } 503 $grade = $assignment->get_user_grade($userid, true, $attemptnumber); 504 $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST); 505 506 if ($assignment->is_blind_marking()) { 507 $prefix = $groupname . get_string('participant', 'assign'); 508 $prefix = str_replace('_', ' ', $prefix); 509 $prefix = clean_filename($prefix . '_' . $assignment->get_uniqueid_for_user($userid) . '_'); 510 } else { 511 $prefix = $groupname . fullname($user); 512 $prefix = str_replace('_', ' ', $prefix); 513 $prefix = clean_filename($prefix . '_' . $assignment->get_uniqueid_for_user($userid) . '_'); 514 } 515 $prefix .= $grade->attemptnumber; 516 517 return $prefix . '.pdf'; 518 } 519 520 /** 521 * This function takes the combined pdf and embeds all the comments and annotations. 522 * 523 * This also moves the annotations and comments from drafts to not drafts. And it will 524 * copy all the images stored to the readonly area, so that they can be viewed online, and 525 * not be overwritten when a new submission is sent. 526 * 527 * @param int|\assign $assignment 528 * @param int $userid 529 * @param int $attemptnumber (-1 means latest attempt) 530 * @return stored_file 531 */ 532 public static function generate_feedback_document($assignment, $userid, $attemptnumber) { 533 534 $assignment = self::get_assignment_from_param($assignment); 535 536 if (!$assignment->can_view_submission($userid)) { 537 \print_error('nopermission'); 538 } 539 if (!$assignment->can_grade()) { 540 \print_error('nopermission'); 541 } 542 543 // Need to generate the page images - first get a combined pdf. 544 $file = self::get_combined_pdf_for_attempt($assignment, $userid, $attemptnumber); 545 if (!$file) { 546 throw new \moodle_exception('Could not generate combined pdf.'); 547 } 548 549 $tmpdir = \make_temp_directory('assignfeedback_editpdf/final/' . self::hash($assignment, $userid, $attemptnumber)); 550 $combined = $tmpdir . '/' . self::COMBINED_PDF_FILENAME; 551 $file->copy_content_to($combined); // Copy the file. 552 553 $pdf = new pdf(); 554 555 $fs = \get_file_storage(); 556 $stamptmpdir = \make_temp_directory('assignfeedback_editpdf/stamps/' . self::hash($assignment, $userid, $attemptnumber)); 557 $grade = $assignment->get_user_grade($userid, true, $attemptnumber); 558 // Copy any new stamps to this instance. 559 if ($files = $fs->get_area_files($assignment->get_context()->id, 560 'assignfeedback_editpdf', 561 'stamps', 562 $grade->id, 563 "filename", 564 false)) { 565 foreach ($files as $file) { 566 $filename = $stamptmpdir . '/' . $file->get_filename(); 567 $file->copy_content_to($filename); // Copy the file. 568 } 569 } 570 571 $pagecount = $pdf->set_pdf($combined); 572 $grade = $assignment->get_user_grade($userid, true, $attemptnumber); 573 page_editor::release_drafts($grade->id); 574 575 for ($i = 0; $i < $pagecount; $i++) { 576 $pdf->copy_page(); 577 $comments = page_editor::get_comments($grade->id, $i, false); 578 $annotations = page_editor::get_annotations($grade->id, $i, false); 579 580 foreach ($comments as $comment) { 581 $pdf->add_comment($comment->rawtext, 582 $comment->x, 583 $comment->y, 584 $comment->width, 585 $comment->colour); 586 } 587 588 foreach ($annotations as $annotation) { 589 $pdf->add_annotation($annotation->x, 590 $annotation->y, 591 $annotation->endx, 592 $annotation->endy, 593 $annotation->colour, 594 $annotation->type, 595 $annotation->path, 596 $stamptmpdir); 597 } 598 } 599 600 fulldelete($stamptmpdir); 601 602 $filename = self::get_downloadable_feedback_filename($assignment, $userid, $attemptnumber); 603 $filename = clean_param($filename, PARAM_FILE); 604 605 $generatedpdf = $tmpdir . '/' . $filename; 606 $pdf->save_pdf($generatedpdf); 607 608 609 $record = new \stdClass(); 610 611 $record->contextid = $assignment->get_context()->id; 612 $record->component = 'assignfeedback_editpdf'; 613 $record->filearea = self::FINAL_PDF_FILEAREA; 614 $record->itemid = $grade->id; 615 $record->filepath = '/'; 616 $record->filename = $filename; 617 618 619 // Only keep one current version of the generated pdf. 620 $fs->delete_area_files($record->contextid, $record->component, $record->filearea, $record->itemid); 621 622 $file = $fs->create_file_from_pathname($record, $generatedpdf); 623 624 // Cleanup. 625 @unlink($generatedpdf); 626 @unlink($combined); 627 @rmdir($tmpdir); 628 629 self::copy_pages_to_readonly_area($assignment, $grade); 630 631 return $file; 632 } 633 634 /** 635 * Copy the pages image to the readonly area. 636 * 637 * @param int|\assign $assignment The assignment. 638 * @param \stdClass $grade The grade record. 639 * @return void 640 */ 641 public static function copy_pages_to_readonly_area($assignment, $grade) { 642 $fs = get_file_storage(); 643 $assignment = self::get_assignment_from_param($assignment); 644 $contextid = $assignment->get_context()->id; 645 $component = 'assignfeedback_editpdf'; 646 $itemid = $grade->id; 647 648 // Get all the pages. 649 $originalfiles = $fs->get_area_files($contextid, $component, self::PAGE_IMAGE_FILEAREA, $itemid); 650 if (empty($originalfiles)) { 651 // Nothing to do here... 652 return; 653 } 654 655 // Delete the old readonly files. 656 $fs->delete_area_files($contextid, $component, self::PAGE_IMAGE_READONLY_FILEAREA, $itemid); 657 658 // Do the copying. 659 foreach ($originalfiles as $originalfile) { 660 $fs->create_file_from_storedfile(array('filearea' => self::PAGE_IMAGE_READONLY_FILEAREA), $originalfile); 661 } 662 } 663 664 /** 665 * This function returns the generated pdf (if it exists). 666 * @param int|\assign $assignment 667 * @param int $userid 668 * @param int $attemptnumber (-1 means latest attempt) 669 * @return stored_file 670 */ 671 public static function get_feedback_document($assignment, $userid, $attemptnumber) { 672 673 $assignment = self::get_assignment_from_param($assignment); 674 675 if (!$assignment->can_view_submission($userid)) { 676 \print_error('nopermission'); 677 } 678 679 $grade = $assignment->get_user_grade($userid, true, $attemptnumber); 680 681 $contextid = $assignment->get_context()->id; 682 $component = 'assignfeedback_editpdf'; 683 $filearea = self::FINAL_PDF_FILEAREA; 684 $itemid = $grade->id; 685 $filepath = '/'; 686 687 $fs = \get_file_storage(); 688 $files = $fs->get_area_files($contextid, 689 $component, 690 $filearea, 691 $itemid, 692 "itemid, filepath, filename", 693 false); 694 if ($files) { 695 return reset($files); 696 } 697 return false; 698 } 699 700 /** 701 * This function deletes the generated pdf for a student. 702 * @param int|\assign $assignment 703 * @param int $userid 704 * @param int $attemptnumber (-1 means latest attempt) 705 * @return bool 706 */ 707 public static function delete_feedback_document($assignment, $userid, $attemptnumber) { 708 709 $assignment = self::get_assignment_from_param($assignment); 710 711 if (!$assignment->can_view_submission($userid)) { 712 \print_error('nopermission'); 713 } 714 if (!$assignment->can_grade()) { 715 \print_error('nopermission'); 716 } 717 718 $grade = $assignment->get_user_grade($userid, true, $attemptnumber); 719 720 $contextid = $assignment->get_context()->id; 721 $component = 'assignfeedback_editpdf'; 722 $filearea = self::FINAL_PDF_FILEAREA; 723 $itemid = $grade->id; 724 725 $fs = \get_file_storage(); 726 return $fs->delete_area_files($contextid, $component, $filearea, $itemid); 727 } 728 729 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |