MDL-52397 editpdf: Fix draft vs nondraft comparison
[moodle.git] / mod / assign / feedback / editpdf / locallib.php
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/>.
17 /**
18  * This file contains the definition for the library class for PDF feedback plugin
19  *
20  *
21  * @package   assignfeedback_editpdf
22  * @copyright 2012 Davo Smith
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 use \assignfeedback_editpdf\document_services;
29 use \assignfeedback_editpdf\page_editor;
31 /**
32  * library class for editpdf feedback plugin extending feedback plugin base class
33  *
34  * @package   assignfeedback_editpdf
35  * @copyright 2012 Davo Smith
36  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37  */
38 class assign_feedback_editpdf extends assign_feedback_plugin {
40     /** @var boolean|null $enabledcache Cached lookup of the is_enabled function */
41     private $enabledcache = null;
43     /**
44      * Get the name of the file feedback plugin
45      * @return string
46      */
47     public function get_name() {
48         return get_string('pluginname', 'assignfeedback_editpdf');
49     }
51     /**
52      * Create a widget for rendering the editor.
53      *
54      * @param int $userid
55      * @param stdClass $grade
56      * @param bool $readonly
57      * @return assignfeedback_editpdf_widget
58      */
59     public function get_widget($userid, $grade, $readonly) {
60         $attempt = -1;
61         if ($grade && $grade->attemptnumber) {
62             $attempt = $grade->attemptnumber;
63         } else {
64             $grade = $this->assignment->get_user_grade($userid, true);
65         }
67         $feedbackfile = document_services::get_feedback_document($this->assignment->get_instance()->id,
68                                                                  $userid,
69                                                                  $attempt);
71         $stampfiles = array();
72         $fs = get_file_storage();
73         $syscontext = context_system::instance();
75         // Copy any new stamps to this instance.
76         if ($files = $fs->get_area_files($syscontext->id,
77                                          'assignfeedback_editpdf',
78                                          'stamps',
79                                          0,
80                                          "filename",
81                                          false)) {
82             foreach ($files as $file) {
83                 $filename = $file->get_filename();
84                 if ($filename !== '.') {
86                     $existingfile = $fs->get_file($this->assignment->get_context()->id,
87                                                   'assignfeedback_editpdf',
88                                                   'stamps',
89                                                   $grade->id,
90                                                   '/',
91                                                   $file->get_filename());
92                     if (!$existingfile) {
93                         $newrecord = new stdClass();
94                         $newrecord->contextid = $this->assignment->get_context()->id;
95                         $newrecord->itemid = $grade->id;
96                         $fs->create_file_from_storedfile($newrecord, $file);
97                     }
98                 }
99             }
100         }
102         // Now get the full list of stamp files for this instance.
103         if ($files = $fs->get_area_files($this->assignment->get_context()->id,
104                                          'assignfeedback_editpdf',
105                                          'stamps',
106                                          $grade->id,
107                                          "filename",
108                                          false)) {
109             foreach ($files as $file) {
110                 $filename = $file->get_filename();
111                 if ($filename !== '.') {
112                     $url = moodle_url::make_pluginfile_url($this->assignment->get_context()->id,
113                                                    'assignfeedback_editpdf',
114                                                    'stamps',
115                                                    $grade->id,
116                                                    '/',
117                                                    $file->get_filename(),
118                                                    false);
119                     array_push($stampfiles, $url->out());
120                 }
121             }
122         }
124         $url = false;
125         $filename = '';
126         if ($feedbackfile) {
127             $url = moodle_url::make_pluginfile_url($this->assignment->get_context()->id,
128                                                    'assignfeedback_editpdf',
129                                                    document_services::FINAL_PDF_FILEAREA,
130                                                    $grade->id,
131                                                    '/',
132                                                    $feedbackfile->get_filename(),
133                                                    false);
134            $filename = $feedbackfile->get_filename();
135         }
137         // Retrieve total number of pages.
138         $pagetotal = document_services::page_number_for_attempt($this->assignment->get_instance()->id,
139                 $userid,
140                 $attempt,
141                 $readonly);
143         $widget = new assignfeedback_editpdf_widget($this->assignment->get_instance()->id,
144                                                     $userid,
145                                                     $attempt,
146                                                     $url,
147                                                     $filename,
148                                                     $stampfiles,
149                                                     $readonly,
150                                                     $pagetotal);
151         return $widget;
152     }
154     /**
155      * Get form elements for grading form
156      *
157      * @param stdClass $grade
158      * @param MoodleQuickForm $mform
159      * @param stdClass $data
160      * @param int $userid
161      * @return bool true if elements were added to the form
162      */
163     public function get_form_elements_for_user($grade, MoodleQuickForm $mform, stdClass $data, $userid) {
164         global $PAGE;
166         $attempt = -1;
167         if ($grade) {
168             $attempt = $grade->attemptnumber;
169         }
171         $files = document_services::list_compatible_submission_files_for_attempt($this->assignment, $userid, $attempt);
172         // Only show the editor if there was a compatible file submitted.
173         if (count($files)) {
175             $renderer = $PAGE->get_renderer('assignfeedback_editpdf');
177             $widget = $this->get_widget($userid, $grade, false);
179             $html = $renderer->render($widget);
180             $mform->addElement('static', 'editpdf', get_string('editpdf', 'assignfeedback_editpdf'), $html);
181             $mform->addHelpButton('editpdf', 'editpdf', 'assignfeedback_editpdf');
182             $mform->addElement('hidden', 'editpdf_source_userid', $userid);
183             $mform->setType('editpdf_source_userid', PARAM_INT);
184             $mform->setConstant('editpdf_source_userid', $userid);
185         }
186     }
188     /**
189      * Check to see if the grade feedback for the pdf has been modified.
190      *
191      * @param stdClass $grade Grade object.
192      * @param stdClass $data Data from the form submission (not used).
193      * @return boolean True if the pdf has been modified, else false.
194      */
195     public function is_feedback_modified(stdClass $grade, stdClass $data) {
196         global $USER;
197         $pagenumbercount = document_services::page_number_for_attempt($this->assignment, $grade->userid, $grade->attemptnumber);
198         for ($i = 0; $i < $pagenumbercount; $i++) {
199             // Select all annotations.
200             $draftannotations = page_editor::get_annotations($grade->id, $i, true);
201             $nondraftannotations = page_editor::get_annotations($grade->id, $i, false);
202             // Check to see if the count is the same.
203             if (count($draftannotations) != count($nondraftannotations)) {
204                 // The count is different so we have a modification.
205                 return true;
206             } else {
207                 $matches = 0;
208                 // Have a closer look and see if the draft files match all the non draft files.
209                 foreach ($nondraftannotations as $ndannotation) {
210                     foreach ($draftannotations as $dannotation) {
211                         foreach ($ndannotation as $key => $value) {
212                             if ($key != 'id' && $value != $dannotation->{$key}) {
213                                 continue 2;
214                             }
215                         }
216                         $matches++;
217                     }
218                 }
219                 if ($matches !== count($nondraftannotations)) {
220                     return true;
221                 }
222             }
223             // Select all comments.
224             $draftcomments = page_editor::get_comments($grade->id, $i, true);
225             $nondraftcomments = page_editor::get_comments($grade->id, $i, false);
226             if (count($draftcomments) != count($nondraftcomments)) {
227                 return true;
228             } else {
229                 // Go for a closer inspection.
230                 $matches = 0;
231                 foreach ($nondraftcomments as $ndcomment) {
232                     foreach ($draftcomments as $dcomment) {
233                         foreach ($ndcomment as $key => $value) {
234                             if ($key != 'id' && $value != $dcomment->{$key}) {
235                                 continue 2;
236                             }
237                         }
238                         $matches++;
239                     }
240                 }
241                 if ($matches !== count($nondraftcomments)) {
242                     return true;
243                 }
244             }
245         }
246         return false;
247     }
249     /**
250      * Generate the pdf.
251      *
252      * @param stdClass $grade
253      * @param stdClass $data
254      * @return bool
255      */
256     public function save(stdClass $grade, stdClass $data) {
257         // Source user id is only added to the form if there was a pdf.
258         if (!empty($data->editpdf_source_userid)) {
259             $sourceuserid = $data->editpdf_source_userid;
260             // Copy drafts annotations and comments if current user is different to sourceuserid.
261             if ($sourceuserid != $grade->userid) {
262                 page_editor::copy_drafts_from_to($this->assignment, $grade, $sourceuserid);
263             }
264         }
265         if (page_editor::has_annotations_or_comments($grade->id, true)) {
266             document_services::generate_feedback_document($this->assignment, $grade->userid, $grade->attemptnumber);
267         }
269         return true;
270     }
272     /**
273      * Display the list of files in the feedback status table.
274      *
275      * @param stdClass $grade
276      * @param bool $showviewlink (Always set to false).
277      * @return string
278      */
279     public function view_summary(stdClass $grade, & $showviewlink) {
280         $showviewlink = false;
281         return $this->view($grade);
282     }
284     /**
285      * Display the list of files in the feedback status table.
286      *
287      * @param stdClass $grade
288      * @return string
289      */
290     public function view(stdClass $grade) {
291         global $PAGE;
292         $html = '';
293         // Show a link to download the pdf.
294         if (page_editor::has_annotations_or_comments($grade->id, false)) {
295             $html = $this->assignment->render_area_files('assignfeedback_editpdf',
296                                                          document_services::FINAL_PDF_FILEAREA,
297                                                          $grade->id);
299             // Also show the link to the read-only interface.
300             $renderer = $PAGE->get_renderer('assignfeedback_editpdf');
301             $widget = $this->get_widget($grade->userid, $grade, true);
303             $html .= $renderer->render($widget);
304         }
305         return $html;
306     }
308     /**
309      * Return true if there are no released comments/annotations.
310      *
311      * @param stdClass $grade
312      */
313     public function is_empty(stdClass $grade) {
314         global $DB;
316         $comments = $DB->count_records('assignfeedback_editpdf_cmnt', array('gradeid'=>$grade->id, 'draft'=>0));
317         $annotations = $DB->count_records('assignfeedback_editpdf_annot', array('gradeid'=>$grade->id, 'draft'=>0));
318         return $comments == 0 && $annotations == 0;
319     }
321     /**
322      * The assignment has been deleted - remove the plugin specific data
323      *
324      * @return bool
325      */
326     public function delete_instance() {
327         global $DB;
328         $grades = $DB->get_records('assign_grades', array('assignment'=>$this->assignment->get_instance()->id), '', 'id');
329         if ($grades) {
330             list($gradeids, $params) = $DB->get_in_or_equal(array_keys($grades), SQL_PARAMS_NAMED);
331             $DB->delete_records_select('assignfeedback_editpdf_annot', 'gradeid ' . $gradeids, $params);
332             $DB->delete_records_select('assignfeedback_editpdf_cmnt', 'gradeid ' . $gradeids, $params);
333         }
334         return true;
335     }
337     /**
338      * Automatically enable or disable editpdf feedback plugin based on
339      * whether the ghostscript path is set correctly.
340      *
341      * @return bool
342      */
343     public function is_enabled() {
344         if ($this->enabledcache === null) {
345             $testpath = assignfeedback_editpdf\pdf::test_gs_path(false);
346             $this->enabledcache = ($testpath->status == assignfeedback_editpdf\pdf::GSPATH_OK);
347         }
348         return $this->enabledcache;
349     }
350     /**
351      * Automatically hide the setting for the editpdf feedback plugin.
352      *
353      * @return bool false
354      */
355     public function is_configurable() {
356         return false;
357     }