diff --git a/mod/assign/feedback/editpdf/ajax.php b/mod/assign/feedback/editpdf/ajax.php index 538d9204187..fa1e21db5f1 100644 --- a/mod/assign/feedback/editpdf/ajax.php +++ b/mod/assign/feedback/editpdf/ajax.php @@ -70,6 +70,7 @@ if ($action === 'pollconversions') { 'filecount' => 0, 'pagecount' => 0, 'pageready' => 0, + 'partial' => false, 'pages' => [], ]; @@ -77,10 +78,13 @@ if ($action === 'pollconversions') { $response->status = $combineddocument->get_status(); $response->filecount = $combineddocument->get_document_count(); - if ($response->status === combined_document::STATUS_READY) { + $readystatuslist = [combined_document::STATUS_READY, combined_document::STATUS_READY_PARTIAL]; + $completestatuslist = [combined_document::STATUS_COMPLETE, combined_document::STATUS_FAILED]; + + if (in_array($response->status, $readystatuslist)) { $combineddocument = document_services::get_combined_pdf_for_attempt($assignment, $userid, $attemptnumber); $response->pagecount = $combineddocument->get_page_count(); - } else if ($response->status === combined_document::STATUS_COMPLETE || $response->status === combined_document::STATUS_FAILED) { + } else if (in_array($response->status, $completestatuslist)) { $pages = document_services::get_page_images_for_attempt($assignment, $userid, $attemptnumber, @@ -95,6 +99,7 @@ if ($action === 'pollconversions') { if ($readonly) { $filearea = document_services::PAGE_IMAGE_READONLY_FILEAREA; } + $response->partial = $combineddocument->is_partial_conversion(); foreach ($pages as $id => $pagefile) { $index = count($response->pages); diff --git a/mod/assign/feedback/editpdf/classes/combined_document.php b/mod/assign/feedback/editpdf/classes/combined_document.php index c0d813c350b..d757599f191 100644 --- a/mod/assign/feedback/editpdf/classes/combined_document.php +++ b/mod/assign/feedback/editpdf/classes/combined_document.php @@ -44,6 +44,11 @@ class combined_document { */ const STATUS_READY = 1; + /** + * Status value representing all documents are ready to be combined as are supported. + */ + const STATUS_READY_PARTIAL = 3; + /** * Status value representing a successful conversion. */ @@ -100,6 +105,7 @@ class combined_document { } $pending = false; + $partial = false; foreach ($this->sourcefiles as $file) { // The combined file has not yet been generated. // Check the status of each source file. @@ -110,12 +116,20 @@ class combined_document { case \core_files\conversion::STATUS_PENDING: $pending = true; break; + + // There are 4 status flags, so the only remaining one is complete which is fine. + case \core_files\conversion::STATUS_FAILED: + $partial = true; + break; } } } if ($pending) { return self::STATUS_PENDING_INPUT; } else { + if ($partial) { + return self::STATUS_READY_PARTIAL; + } return self::STATUS_READY; } } @@ -131,6 +145,20 @@ class combined_document { return $this; } + /** + * Return true of the combined file contained only some of the submission files. + * + * @return boolean + */ + public function is_partial_conversion() { + $combinedfile = $this->get_combined_file(); + if (empty($combinedfile)) { + return false; + } + $filearea = $combinedfile->get_filearea(); + return $filearea == document_services::PARTIAL_PDF_FILEAREA; + } + /** * Retrieve the completed combined file. * @@ -210,11 +238,12 @@ class combined_document { global $CFG; $currentstatus = $this->get_status(); + $readystatuslist = [self::STATUS_READY, self::STATUS_READY_PARTIAL]; if ($currentstatus === self::STATUS_FAILED) { $this->store_empty_document($contextid, $itemid); return $this; - } else if ($currentstatus !== self::STATUS_READY) { + } else if (!in_array($currentstatus, $readystatuslist)) { // The document is either: // * already combined; or // * pending input being fully converted; or @@ -273,7 +302,7 @@ class combined_document { } // Store the newly created file as a stored_file. - $this->store_combined_file($tmpfile, $contextid, $itemid); + $this->store_combined_file($tmpfile, $contextid, $itemid, ($currentstatus == self::STATUS_READY_PARTIAL)); // Note the verified page count. $this->pagecount = $verifypagecount; @@ -298,11 +327,12 @@ class combined_document { * @param string $tmpfile The path to the file on disk to be stored. * @param int $contextid The contextid for the file to be stored under * @param int $itemid The itemid for the file to be stored under + * @param boolean $partial The combined pdf contains only some of the source files. * @return $this */ - protected function store_combined_file($tmpfile, $contextid, $itemid) { + protected function store_combined_file($tmpfile, $contextid, $itemid, $partial = false) { // Store the file. - $record = $this->get_stored_file_record($contextid, $itemid); + $record = $this->get_stored_file_record($contextid, $itemid, $partial); $fs = get_file_storage(); // Delete existing files first. @@ -352,12 +382,14 @@ class combined_document { return $this->pagecount; } - if ($this->get_status() === self::STATUS_FAILED) { + $status = $this->get_status(); + + if ($status === self::STATUS_FAILED) { // The empty document will be returned. return 1; } - if ($this->get_status() !== self::STATUS_COMPLETE) { + if ($status !== self::STATUS_COMPLETE) { // No pages yet. return 0; } @@ -394,13 +426,18 @@ class combined_document { * * @param int $contextid The contextid for the file to be stored under * @param int $itemid The itemid for the file to be stored under + * @param boolean $partial The combined file contains only some of the source files. * @return stdClass */ - protected function get_stored_file_record($contextid, $itemid) { + protected function get_stored_file_record($contextid, $itemid, $partial = false) { + $filearea = document_services::COMBINED_PDF_FILEAREA; + if ($partial) { + $filearea = document_services::PARTIAL_PDF_FILEAREA; + } return (object) [ 'contextid' => $contextid, 'component' => 'assignfeedback_editpdf', - 'filearea' => document_services::COMBINED_PDF_FILEAREA, + 'filearea' => $filearea, 'itemid' => $itemid, 'filepath' => '/', 'filename' => document_services::COMBINED_PDF_FILENAME, diff --git a/mod/assign/feedback/editpdf/classes/document_services.php b/mod/assign/feedback/editpdf/classes/document_services.php index 384ccdd2bdd..45b4083f18f 100644 --- a/mod/assign/feedback/editpdf/classes/document_services.php +++ b/mod/assign/feedback/editpdf/classes/document_services.php @@ -42,6 +42,8 @@ class document_services { const FINAL_PDF_FILEAREA = 'download'; /** File area for combined pdf */ const COMBINED_PDF_FILEAREA = 'combined'; + /** File area for partial combined pdf */ + const PARTIAL_PDF_FILEAREA = 'partial'; /** File area for importing html */ const IMPORT_HTML_FILEAREA = 'importhtml'; /** File area for page images */ @@ -261,15 +263,23 @@ EOD; $submission = $assignment->get_user_submission($userid, false, $attemptnumber); } + $contextid = $assignment->get_context()->id; $component = 'assignfeedback_editpdf'; $filearea = self::COMBINED_PDF_FILEAREA; + $partialfilearea = self::PARTIAL_PDF_FILEAREA; $itemid = $grade->id; $filepath = '/'; $filename = self::COMBINED_PDF_FILENAME; $fs = get_file_storage(); - $combinedpdf = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename); + $partialpdf = $fs->get_file($contextid, $component, $partialfilearea, $itemid, $filepath, $filename); + if (!empty($partialpdf)) { + $combinedpdf = $partialpdf; + } else { + $combinedpdf = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename); + } + if ($combinedpdf && $submission) { if ($combinedpdf->get_timemodified() < $submission->timemodified) { // The submission has been updated since the PDF was generated. @@ -381,6 +391,7 @@ EOD; $tmpdir = \make_temp_directory('assignfeedback_editpdf/pageimages/' . self::hash($assignment, $userid, $attemptnumber)); $combined = $tmpdir . '/' . self::COMBINED_PDF_FILENAME; + $document->get_combined_file()->copy_content_to($combined); // Copy the file. $pdf = new pdf(); diff --git a/mod/assign/feedback/editpdf/classes/renderer.php b/mod/assign/feedback/editpdf/classes/renderer.php index 882fdc4d727..2d5ae5a4ce2 100644 --- a/mod/assign/feedback/editpdf/classes/renderer.php +++ b/mod/assign/feedback/editpdf/classes/renderer.php @@ -268,7 +268,8 @@ class assignfeedback_editpdf_renderer extends plugin_renderer_base { 'stamp', 'stamppicker', 'cannotopenpdf', - 'pagenumber' + 'pagenumber', + 'partialwarning' ), 'assignfeedback_editpdf'); return $html; diff --git a/mod/assign/feedback/editpdf/classes/task/convert_submissions.php b/mod/assign/feedback/editpdf/classes/task/convert_submissions.php index 68295fd840e..be6b0a14146 100644 --- a/mod/assign/feedback/editpdf/classes/task/convert_submissions.php +++ b/mod/assign/feedback/editpdf/classes/task/convert_submissions.php @@ -102,10 +102,9 @@ class convert_submissions extends scheduled_task { foreach ($users as $userid) { try { $combineddocument = document_services::get_combined_pdf_for_attempt($assignment, $userid, $attemptnumber); - $status = $combineddocument->get_status(); - switch ($combineddocument->get_status()) { case combined_document::STATUS_READY: + case combined_document::STATUS_READY_PARTIAL: case combined_document::STATUS_PENDING_INPUT: // The document has not been converted yet or is somehow still ready. continue 2; diff --git a/mod/assign/feedback/editpdf/lang/en/assignfeedback_editpdf.php b/mod/assign/feedback/editpdf/lang/en/assignfeedback_editpdf.php index 0dbffbacd65..a8f7c0ee520 100644 --- a/mod/assign/feedback/editpdf/lang/en/assignfeedback_editpdf.php +++ b/mod/assign/feedback/editpdf/lang/en/assignfeedback_editpdf.php @@ -72,6 +72,7 @@ $string['output'] = 'Output:'; $string['pagenumber'] = 'Page {$a}'; $string['pagexofy'] = 'Page {$a->page} of {$a->total}'; $string['pen'] = 'Pen'; +$string['partialwarning'] = 'Some of the submission files must be downloaded.'; $string['pluginname'] = 'Annotate PDF'; $string['privacy:metadata:colourpurpose'] = 'Colour of the comment or annotation'; $string['privacy:metadata:conversionpurpose'] = 'Files are converted to PDFs to allow for annotations.'; diff --git a/mod/assign/feedback/editpdf/styles.css b/mod/assign/feedback/editpdf/styles.css index 844c9436eac..bae19d98a19 100644 --- a/mod/assign/feedback/editpdf/styles.css +++ b/mod/assign/feedback/editpdf/styles.css @@ -67,7 +67,7 @@ display: none; position: absolute; left: 20px; - top: 60px; + top: 120px; } .yui3-colourpicker-hidden, diff --git a/mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-debug.js b/mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-debug.js index bea07f58bb8..e09ac6c9ead 100644 --- a/mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-debug.js +++ b/mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-debug.js @@ -3829,6 +3829,21 @@ EDITOR.prototype = { }); }, + /** + * Display an error in a small part of the page (don't block everything). + * + * @param string The error text. + * @protected + * @method warning + */ + warning: function(message) { + var drawingregion = this.get_dialogue_element(SELECTOR.DRAWINGREGION); + + var warningelement = Y.Node.create(''); + warningelement.setHTML(message); + drawingregion.prepend(warningelement); + }, + /** * The info about all pages in the pdf has been returned. * @@ -3837,7 +3852,8 @@ EDITOR.prototype = { * @method prepare_pages_for_display */ prepare_pages_for_display: function(data) { - var i, j, comment, error; + var i, j, comment, error, annotation, readonly; + if (!data.pagecount) { if (this.dialogue) { this.dialogue.hide(); @@ -3863,11 +3879,17 @@ EDITOR.prototype = { comment.rawtext); } for (j = 0; j < this.pages[i].annotations.length; j++) { - data = this.pages[i].annotations[j]; - this.pages[i].annotations[j] = this.create_annotation(data.type, data); + annotation = this.pages[i].annotations[j]; + this.pages[i].annotations[j] = this.create_annotation(annotation.type, annotation); } } + readonly = this.get('readonly'); + if (!readonly && data.partial) { + // Warn about non converted files, but only for teachers. + this.warning(M.util.get_string('partialwarning', 'assignfeedback_editpdf')); + } + // Update the ui. if (this.quicklist) { this.quicklist.load(); @@ -4817,6 +4839,7 @@ M.assignfeedback_editpdf.editor.init = M.assignfeedback_editpdf.editor.init || f "querystring-stringify-simple", "moodle-core-notification-dialog", "moodle-core-notification-alert", + "moodle-core-notification-warning", "moodle-core-notification-exception", "moodle-core-notification-ajaxexception" ] diff --git a/mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-min.js b/mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-min.js index bb0f77debe2..2a72d8f964c 100644 --- a/mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-min.js +++ b/mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-min.js @@ -4,6 +4,6 @@ M.assignfeedback_editpdf.drawable(this.editor),r,i,s;return i=new M.assignfeedba ,this),n.delegate("key",this.callback_handler,"down:13","button",this),this.set("headerText",M.util.get_string("stamppicker","assignfeedback_editpdf")),this.set("bodyContent",n),O.superclass.initializer.call(this,t)},callback_handler:function(t){t.preventDefault();var n=this.get("callback"),r=this.get("context"),i;this.hide(),i=e.bind(n,r,t),i()}},{NAME:A,ATTRS:{stamps:{value:[]},callback:{value:null},context:{value:null}}}),M.assignfeedback_editpdf=M.assignfeedback_editpdf||{},M.assignfeedback_editpdf.stamppicker=O;var _="Commentmenu",D;D=function(e){D.superclass.constructor.apply(this,[e])},e.extend(D,M.assignfeedback_editpdf.dropdown,{initializer:function(t){var n,r,i,s;s=this.get("comment"),n=e.Node.create('