de9c770797ac077a83b01d86fac5f2e3536b7bae
[moodle.git] / mod / assign / feedback / editpdf / classes / page_editor.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 editor class 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  */
25 namespace assignfeedback_editpdf;
27 /**
28  * This class performs crud operations on comments and annotations from a page of a response.
29  *
30  * No capability checks are done - they should be done by the calling class.
31  *
32  * @package   assignfeedback_editpdf
33  * @copyright 2012 Davo Smith
34  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35  */
36 class page_editor {
38     /**
39      * Get all comments for a page.
40      * @param int $gradeid
41      * @param int $pageno
42      * @param bool $draft
43      * @return comment[]
44      */
45     public static function get_comments($gradeid, $pageno, $draft) {
46         global $DB;
48         $comments = array();
49         $params = array('gradeid'=>$gradeid, 'pageno'=>$pageno, 'draft'=>1);
50         if (!$draft) {
51             $params['draft'] = 0;
52         }
53         // Fetch comments ordered by position on the page.
54         $records = $DB->get_records('assignfeedback_editpdf_cmnt', $params, 'y, x');
55         foreach ($records as $record) {
56             array_push($comments, new comment($record));
57         }
59         return $comments;
60     }
62     /**
63      * Set all comments for a page.
64      * @param int $gradeid
65      * @param int $pageno
66      * @param comment[] $comments
67      * @return int - the number of comments.
68      */
69     public static function set_comments($gradeid, $pageno, $comments) {
70         global $DB;
72         $DB->delete_records('assignfeedback_editpdf_cmnt', array('gradeid'=>$gradeid, 'pageno'=>$pageno, 'draft'=>1));
74         $added = 0;
75         foreach ($comments as $record) {
76             // Force these.
77             if (!($record instanceof comment)) {
78                 $comment = new comment($record);
79             } else {
80                 $comment = $record;
81             }
82             if (trim($comment->rawtext) === '') {
83                 continue;
84             }
85             $comment->gradeid = $gradeid;
86             $comment->pageno = $pageno;
87             $comment->draft = 1;
88             if (self::add_comment($comment)) {
89                 $added++;
90             }
91         }
93         return $added;
94     }
96     /**
97      * Get a single comment by id.
98      * @param int $commentid
99      * @return comment or false
100      */
101     public static function get_comment($commentid) {
102         $record = $DB->get_record('assignfeedback_editpdf_cmnt', array('id'=>$commentid), '*', IGNORE_MISSING);
103         if ($record) {
104             return new comment($record);
105         }
106         return false;
107     }
109     /**
110      * Add a comment to a page.
111      * @param comment $comment
112      * @return bool
113      */
114     public static function add_comment(comment $comment) {
115         global $DB;
116         $comment->id = null;
117         return $DB->insert_record('assignfeedback_editpdf_cmnt', $comment);
118     }
120     /**
121      * Remove a comment from a page.
122      * @param int $commentid
123      * @return bool
124      */
125     public static function remove_comment($commentid) {
126         global $DB;
127         return $DB->delete_records('assignfeedback_editpdf_cmnt', array('id'=>$commentid));
128     }
130     /**
131      * Get all annotations for a page.
132      * @param int $gradeid
133      * @param int $pageno
134      * @param bool $draft
135      * @return annotation[]
136      */
137     public static function get_annotations($gradeid, $pageno, $draft) {
138         global $DB;
140         $params = array('gradeid'=>$gradeid, 'pageno'=>$pageno, 'draft'=>1);
141         if (!$draft) {
142             $params['draft'] = 0;
143         }
144         $annotations = array();
145         $records = $DB->get_records('assignfeedback_editpdf_annot', $params);
146         foreach ($records as $record) {
147             array_push($annotations, new annotation($record));
148         }
150         return $annotations;
151     }
153     /**
154      * Set all annotations for a page.
155      * @param int $gradeid
156      * @param int $pageno
157      * @param annotation[] $annotations
158      * @return int - the number of annotations.
159      */
160     public static function set_annotations($gradeid, $pageno, $annotations) {
161         global $DB;
163         $DB->delete_records('assignfeedback_editpdf_annot', array('gradeid' => $gradeid, 'pageno' => $pageno, 'draft' => 1));
164         $added = 0;
165         foreach ($annotations as $record) {
166             // Force these.
167             if (!($record instanceof annotation)) {
168                 $annotation = new annotation($record);
169             } else {
170                 $annotation = $record;
171             }
172             $annotation->gradeid = $gradeid;
173             $annotation->pageno = $pageno;
174             $annotation->draft = 1;
175             if (self::add_annotation($annotation)) {
176                 $added++;
177             }
178         }
180         return $added;
181     }
183     /**
184      * Get a single annotation by id.
185      * @param int $annotationid
186      * @return annotation or false
187      */
188     public static function get_annotation($annotationid) {
189         global $DB;
191         $record = $DB->get_record('assignfeedback_editpdf_annot', array('id'=>$annotationid), '*', IGNORE_MISSING);
192         if ($record) {
193             return new annotation($record);
194         }
195         return false;
196     }
198     /**
199      * Unrelease drafts
200      * @param int $gradeid
201      * @return bool
202      */
203     public static function unrelease_drafts($gradeid) {
204         global $DB;
206         // Delete the non-draft annotations and comments.
207         $result = $DB->delete_records('assignfeedback_editpdf_cmnt', array('gradeid'=>$gradeid, 'draft'=>0));
208         $result = $DB->delete_records('assignfeedback_editpdf_annot', array('gradeid'=>$gradeid, 'draft'=>0)) && $result;
209         return $result;
210     }
212     /**
213      * Release the draft comments and annotations to students.
214      * @param int $gradeid
215      * @return bool
216      */
217     public static function release_drafts($gradeid) {
218         global $DB;
220         // Delete the previous non-draft annotations and comments.
221         $DB->delete_records('assignfeedback_editpdf_cmnt', array('gradeid'=>$gradeid, 'draft'=>0));
222         $DB->delete_records('assignfeedback_editpdf_annot', array('gradeid'=>$gradeid, 'draft'=>0));
224         // Copy all the draft annotations and comments to non-drafts.
225         $records = $DB->get_records('assignfeedback_editpdf_annot', array('gradeid'=>$gradeid, 'draft'=>1));
226         foreach ($records as $record) {
227             unset($record->id);
228             $record->draft = 0;
229             $DB->insert_record('assignfeedback_editpdf_annot', $record);
230         }
231         $records = $DB->get_records('assignfeedback_editpdf_cmnt', array('gradeid'=>$gradeid, 'draft'=>1));
232         foreach ($records as $record) {
233             unset($record->id);
234             $record->draft = 0;
235             $DB->insert_record('assignfeedback_editpdf_cmnt', $record);
236         }
238         return true;
239     }
241     /**
242      * Has annotations or comments.
243      * @param int $gradeid
244      * @return bool
245      */
246     public static function has_annotations_or_comments($gradeid, $includedraft) {
247         global $DB;
248         $params = array('gradeid'=>$gradeid);
249         if (!$includedraft) {
250             $params['draft'] = 0;
251         }
252         if ($DB->count_records('assignfeedback_editpdf_cmnt', $params)) {
253             return true;
254         }
255         if ($DB->count_records('assignfeedback_editpdf_annot', $params)) {
256             return true;
257         }
258         return false;
259     }
261     /**
262      * Aborts all draft annotations and reverts to the last version released to students.
263      * @param int $gradeid
264      * @return bool
265      */
266     public static function revert_drafts($gradeid) {
267         global $DB;
269         // Delete the previous non-draft annotations and comments.
270         $DB->delete_records('assignfeedback_editpdf_cmnt', array('gradeid'=>$gradeid, 'draft'=>1));
271         $DB->delete_records('assignfeedback_editpdf_annot', array('gradeid'=>$gradeid, 'draft'=>1));
273         // Copy all the draft annotations and comments to non-drafts.
274         $records = $DB->get_records('assignfeedback_editpdf_annot', array('gradeid'=>$gradeid, 'draft'=>0));
275         foreach ($records as $record) {
276             unset($record->id);
277             $record->draft = 0;
278             $DB->insert_record('assignfeedback_editpdf_annot', $record);
279         }
280         $records = $DB->get_records('assignfeedback_editpdf_cmnt', array('gradeid'=>$gradeid, 'draft'=>0));
281         foreach ($records as $record) {
282             unset($record->id);
283             $record->draft = 0;
284             $DB->insert_record('assignfeedback_editpdf_annot', $record);
285         }
287         return true;
288     }
290     /**
291      * Add a annotation to a page.
292      * @param annotation $annotation
293      * @return bool
294      */
295     public static function add_annotation(annotation $annotation) {
296         global $DB;
298         $annotation->id = null;
299         return $DB->insert_record('assignfeedback_editpdf_annot', $annotation);
300     }
302     /**
303      * Remove a annotation from a page.
304      * @param int $annotationid
305      * @return bool
306      */
307     public static function remove_annotation($annotationid) {
308         global $DB;
310         return $DB->delete_records('assignfeedback_editpdf_annot', array('id'=>$annotationid));
311     }
313     /**
314      * Copy annotations, comments, pages, and other required content from the source user to the current group member
315      * being procssed when using applytoall.
316      *
317      * @param int|\assign $assignment
318      * @param stdClass $grade
319      * @param int $sourceuserid
320      * @return bool
321      */
322     public static function copy_drafts_from_to($assignment, $grade, $sourceuserid) {
323         global $DB;
325         // Delete any existing annotations and comments from current user.
326         $DB->delete_records('assignfeedback_editpdf_annot', array('gradeid' => $grade->id));
327         $DB->delete_records('assignfeedback_editpdf_cmnt', array('gradeid' => $grade->id));
328         // Get gradeid, annotations and comments from sourceuserid.
329         $sourceusergrade = $assignment->get_user_grade($sourceuserid, true, $grade->attemptnumber);
330         $annotations = $DB->get_records('assignfeedback_editpdf_annot', array('gradeid' => $sourceusergrade->id, 'draft' => 1));
331         $comments = $DB->get_records('assignfeedback_editpdf_cmnt', array('gradeid' => $sourceusergrade->id, 'draft' => 1));
332         $contextid = $assignment->get_context()->id;
333         $sourceitemid = $sourceusergrade->id;
335         // Add annotations and comments to current user to generate feedback file.
336         foreach ($annotations as $annotation) {
337             $annotation->gradeid = $grade->id;
338             $DB->insert_record('assignfeedback_editpdf_annot', $annotation);
339         }
340         foreach ($comments as $comment) {
341             $comment->gradeid = $grade->id;
342             $DB->insert_record('assignfeedback_editpdf_cmnt', $comment);
343         }
345         $fs = get_file_storage();
347         // Copy the stamp files.
348         self::replace_files_from_to($fs, $contextid, $sourceitemid, $grade->id, document_services::STAMPS_FILEAREA, true);
350         // Copy the PAGE_IMAGE_FILEAREA files.
351         self::replace_files_from_to($fs, $contextid, $sourceitemid, $grade->id, document_services::PAGE_IMAGE_FILEAREA);
353         return true;
354     }
356     /**
357      * Replace the area files in the specified area with those in the source item id.
358      *
359      * @param \file_storage $fs The file storage class
360      * @param int $contextid The ID of the context for the assignment.
361      * @param int $sourceitemid The itemid to copy from - typically the source grade id.
362      * @param int $itemid The itemid to copy to - typically the target grade id.
363      * @param string $area The file storage area.
364      * @param bool $includesubdirs Whether to copy the content of sub-directories too.
365      */
366     public static function replace_files_from_to($fs, $contextid, $sourceitemid, $itemid, $area, $includesubdirs = false) {
367         $component = 'assignfeedback_editpdf';
368         // Remove the existing files within this area.
369         $fs->delete_area_files($contextid, $component, $area, $itemid);
371         // Copy the files from the source area.
372         if ($files = $fs->get_area_files($contextid, $component, $area, $sourceitemid,
373                                          "filename", $includesubdirs)) {
374             foreach ($files as $file) {
375                 $newrecord = new \stdClass();
376                 $newrecord->contextid = $contextid;
377                 $newrecord->itemid = $itemid;
378                 $fs->create_file_from_storedfile($newrecord, $file);
379             }
380         }
381     }
383     /**
384      * Delete the draft annotations and comments.
385      *
386      * This is intended to be used when the version of the PDF has changed and the annotations
387      * might not be relevant any more, therefore we should delete them.
388      *
389      * @param int $gradeid The grade ID.
390      * @return bool
391      */
392     public static function delete_draft_content($gradeid) {
393         global $DB;
394         $conditions = array('gradeid' => $gradeid, 'draft' => 1);
395         $result = $DB->delete_records('assignfeedback_editpdf_annot', $conditions);
396         $result = $result && $DB->delete_records('assignfeedback_editpdf_cmnt', $conditions);
397         return $result;
398     }