| 1 | efrain | 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 definition for the library class for file feedback plugin
 | 
        
           |  |  | 19 |  *
 | 
        
           |  |  | 20 |  *
 | 
        
           |  |  | 21 |  * @package   assignfeedback_file
 | 
        
           |  |  | 22 |  * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
 | 
        
           |  |  | 23 |  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 24 |  */
 | 
        
           |  |  | 25 |   | 
        
           |  |  | 26 | defined('MOODLE_INTERNAL') || die();
 | 
        
           |  |  | 27 |   | 
        
           |  |  | 28 | use mod_assign\output\assign_header;
 | 
        
           |  |  | 29 |   | 
        
           |  |  | 30 | /**
 | 
        
           |  |  | 31 |  * library class for importing feedback files from a zip
 | 
        
           |  |  | 32 |  *
 | 
        
           |  |  | 33 |  * @package   assignfeedback_file
 | 
        
           |  |  | 34 |  * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
 | 
        
           |  |  | 35 |  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 36 |  */
 | 
        
           |  |  | 37 | class assignfeedback_file_zip_importer {
 | 
        
           |  |  | 38 |   | 
        
           |  |  | 39 |     /**
 | 
        
           |  |  | 40 |      * Is this filename valid (contains a unique participant ID) for import?
 | 
        
           |  |  | 41 |      *
 | 
        
           |  |  | 42 |      * @param assign $assignment - The assignment instance
 | 
        
           |  |  | 43 |      * @param stored_file $fileinfo - The fileinfo
 | 
        
           |  |  | 44 |      * @param array $participants - A list of valid participants for this module indexed by unique_id or group id.
 | 
        
           |  |  | 45 |      * @param array $users - Set to array with the user(s) that matches by participant id
 | 
        
           |  |  | 46 |      * @param assign_plugin $plugin - Set to the plugin that exported the file
 | 
        
           |  |  | 47 |      * @param string $filename - Set to truncated filename (prefix stripped)
 | 
        
           |  |  | 48 |      * @return bool If the participant Id can be extracted and this is a valid user
 | 
        
           |  |  | 49 |      */
 | 
        
           |  |  | 50 |     public function is_valid_filename_for_import($assignment, $fileinfo, $participants, & $users, & $plugin, & $filename) {
 | 
        
           |  |  | 51 |         if ($fileinfo->is_directory()) {
 | 
        
           |  |  | 52 |             return false;
 | 
        
           |  |  | 53 |         }
 | 
        
           |  |  | 54 |   | 
        
           |  |  | 55 |         // Ignore hidden files.
 | 
        
           |  |  | 56 |         if (strpos($fileinfo->get_filename(), '.') === 0) {
 | 
        
           |  |  | 57 |             return false;
 | 
        
           |  |  | 58 |         }
 | 
        
           |  |  | 59 |         // Ignore hidden files.
 | 
        
           |  |  | 60 |         if (strpos($fileinfo->get_filename(), '~') === 0) {
 | 
        
           |  |  | 61 |             return false;
 | 
        
           |  |  | 62 |         }
 | 
        
           |  |  | 63 |   | 
        
           |  |  | 64 |         // Break the full path-name into path parts.
 | 
        
           |  |  | 65 |         $pathparts = explode('/', $fileinfo->get_filepath() . $fileinfo->get_filename());
 | 
        
           |  |  | 66 |   | 
        
           |  |  | 67 |         while (!empty($pathparts)) {
 | 
        
           |  |  | 68 |             // Get the next path part and break it up by underscores.
 | 
        
           |  |  | 69 |             $pathpart = array_shift($pathparts);
 | 
        
           |  |  | 70 |             $info = explode('_', $pathpart, 5);
 | 
        
           |  |  | 71 |   | 
        
           |  |  | 72 |             // Expected format for the directory names in $pathpart is fullname_userid_plugintype_pluginname (as created by zip
 | 
        
           |  |  | 73 |             // export in Moodle >= 4.1) resp. fullname_userid_plugintype_pluginname_ (as created by earlier versions). We ensure
 | 
        
           |  |  | 74 |             // compatibility with both ways here.
 | 
        
           |  |  | 75 |             if (count($info) < 4) {
 | 
        
           |  |  | 76 |                 continue;
 | 
        
           |  |  | 77 |             }
 | 
        
           |  |  | 78 |   | 
        
           |  |  | 79 |             // Check the participant id.
 | 
        
           |  |  | 80 |             $participantid = $info[1];
 | 
        
           |  |  | 81 |   | 
        
           |  |  | 82 |             if (!is_numeric($participantid)) {
 | 
        
           |  |  | 83 |                 continue;
 | 
        
           |  |  | 84 |             }
 | 
        
           |  |  | 85 |   | 
        
           |  |  | 86 |             // Convert to int.
 | 
        
           |  |  | 87 |             $participantid += 0;
 | 
        
           |  |  | 88 |   | 
        
           |  |  | 89 |             if (empty($participants[$participantid])) {
 | 
        
           |  |  | 90 |                 continue;
 | 
        
           |  |  | 91 |             }
 | 
        
           |  |  | 92 |   | 
        
           |  |  | 93 |             // Set user, which is by reference, so is used by the calling script.
 | 
        
           |  |  | 94 |             $users = $participants[$participantid];
 | 
        
           |  |  | 95 |   | 
        
           |  |  | 96 |             // Set the plugin. This by reference, and is used by the calling script.
 | 
        
           |  |  | 97 |             $plugin = $assignment->get_plugin_by_type($info[2], $info[3]);
 | 
        
           |  |  | 98 |   | 
        
           |  |  | 99 |             if (!$plugin) {
 | 
        
           |  |  | 100 |                 continue;
 | 
        
           |  |  | 101 |             }
 | 
        
           |  |  | 102 |   | 
        
           |  |  | 103 |             // To get clean path names, we need to have at least an empty entry for $info[4].
 | 
        
           |  |  | 104 |             if (count($info) == 4) {
 | 
        
           |  |  | 105 |                 $info[4] = '';
 | 
        
           |  |  | 106 |             }
 | 
        
           |  |  | 107 |             // Take any remaining text in this part and put it back in the path parts array.
 | 
        
           |  |  | 108 |             array_unshift($pathparts, $info[4]);
 | 
        
           |  |  | 109 |   | 
        
           |  |  | 110 |             // Combine the remaining parts and set it as the filename.
 | 
        
           |  |  | 111 |             // Note that filename is a 'by reference' variable, so we need to set it before returning.
 | 
        
           |  |  | 112 |             $filename = implode('/', $pathparts);
 | 
        
           |  |  | 113 |   | 
        
           |  |  | 114 |             return true;
 | 
        
           |  |  | 115 |         }
 | 
        
           |  |  | 116 |   | 
        
           |  |  | 117 |         return false;
 | 
        
           |  |  | 118 |     }
 | 
        
           |  |  | 119 |   | 
        
           |  |  | 120 |     /**
 | 
        
           |  |  | 121 |      * Does this file exist in any of the current files supported by this plugin for this user?
 | 
        
           |  |  | 122 |      *
 | 
        
           |  |  | 123 |      * @param assign $assignment - The assignment instance
 | 
        
           |  |  | 124 |      * @param array|stdClass $users The user(s) matching this uploaded file
 | 
        
           |  |  | 125 |      * @param assign_plugin $plugin The matching plugin from the filename
 | 
        
           |  |  | 126 |      * @param string $filename The parsed filename from the zip
 | 
        
           |  |  | 127 |      * @param stored_file $fileinfo The info about the extracted file from the zip
 | 
        
           |  |  | 128 |      * @return bool - True if the file has been modified or is new
 | 
        
           |  |  | 129 |      */
 | 
        
           |  |  | 130 |     public function is_file_modified($assignment, $users, $plugin, $filename, $fileinfo) {
 | 
        
           |  |  | 131 |         $sg = null;
 | 
        
           |  |  | 132 |   | 
        
           |  |  | 133 |         if (is_array($users)) {
 | 
        
           |  |  | 134 |             $user = $users[0];
 | 
        
           |  |  | 135 |         } else {
 | 
        
           |  |  | 136 |             $user = $users;
 | 
        
           |  |  | 137 |         }
 | 
        
           |  |  | 138 |   | 
        
           |  |  | 139 |         if ($plugin->get_subtype() == 'assignsubmission') {
 | 
        
           |  |  | 140 |             if ($assignment->get_instance()->teamsubmission) {
 | 
        
           |  |  | 141 |                 $sg = $assignment->get_group_submission($user->id, 0, false);
 | 
        
           |  |  | 142 |             } else {
 | 
        
           |  |  | 143 |                 $sg = $assignment->get_user_submission($user->id, false);
 | 
        
           |  |  | 144 |             }
 | 
        
           |  |  | 145 |         } else if ($plugin->get_subtype() == 'assignfeedback') {
 | 
        
           |  |  | 146 |             $sg = $assignment->get_user_grade($user->id, false);
 | 
        
           |  |  | 147 |         } else {
 | 
        
           |  |  | 148 |             return false;
 | 
        
           |  |  | 149 |         }
 | 
        
           |  |  | 150 |   | 
        
           |  |  | 151 |         if (!$sg) {
 | 
        
           |  |  | 152 |             return true;
 | 
        
           |  |  | 153 |         }
 | 
        
           |  |  | 154 |         foreach ($plugin->get_files($sg, $user) as $pluginfilename => $file) {
 | 
        
           |  |  | 155 |             if ($pluginfilename == $filename) {
 | 
        
           |  |  | 156 |                 // Extract the file and compare hashes.
 | 
        
           |  |  | 157 |                 $contenthash = '';
 | 
        
           |  |  | 158 |                 if (is_array($file)) {
 | 
        
           |  |  | 159 |                     $content = reset($file);
 | 
        
           |  |  | 160 |                     $contenthash = file_storage::hash_from_string($content);
 | 
        
           |  |  | 161 |                 } else {
 | 
        
           |  |  | 162 |                     $contenthash = $file->get_contenthash();
 | 
        
           |  |  | 163 |                 }
 | 
        
           |  |  | 164 |                 if ($contenthash != $fileinfo->get_contenthash()) {
 | 
        
           |  |  | 165 |                     return true;
 | 
        
           |  |  | 166 |                 } else {
 | 
        
           |  |  | 167 |                     return false;
 | 
        
           |  |  | 168 |                 }
 | 
        
           |  |  | 169 |             }
 | 
        
           |  |  | 170 |         }
 | 
        
           |  |  | 171 |         return true;
 | 
        
           |  |  | 172 |     }
 | 
        
           |  |  | 173 |   | 
        
           |  |  | 174 |     /**
 | 
        
           |  |  | 175 |      * Delete all temp files used when importing a zip
 | 
        
           |  |  | 176 |      *
 | 
        
           |  |  | 177 |      * @param int $contextid - The context id of this assignment instance
 | 
        
           |  |  | 178 |      * @return bool true if all files were deleted
 | 
        
           |  |  | 179 |      */
 | 
        
           |  |  | 180 |     public function delete_import_files($contextid) {
 | 
        
           |  |  | 181 |         global $USER;
 | 
        
           |  |  | 182 |   | 
        
           |  |  | 183 |         $fs = get_file_storage();
 | 
        
           |  |  | 184 |   | 
        
           |  |  | 185 |         return $fs->delete_area_files($contextid,
 | 
        
           |  |  | 186 |                                       'assignfeedback_file',
 | 
        
           |  |  | 187 |                                       ASSIGNFEEDBACK_FILE_IMPORT_FILEAREA,
 | 
        
           |  |  | 188 |                                       $USER->id);
 | 
        
           |  |  | 189 |     }
 | 
        
           |  |  | 190 |   | 
        
           |  |  | 191 |     /**
 | 
        
           |  |  | 192 |      * Extract the uploaded zip to a temporary import area for this user
 | 
        
           |  |  | 193 |      *
 | 
        
           |  |  | 194 |      * @param stored_file $zipfile The uploaded file
 | 
        
           |  |  | 195 |      * @param int $contextid The context for this assignment
 | 
        
           |  |  | 196 |      * @return bool - True if the files were unpacked
 | 
        
           |  |  | 197 |      */
 | 
        
           |  |  | 198 |     public function extract_files_from_zip($zipfile, $contextid) {
 | 
        
           |  |  | 199 |         global $USER;
 | 
        
           |  |  | 200 |   | 
        
           |  |  | 201 |         $feedbackfilesupdated = 0;
 | 
        
           |  |  | 202 |         $feedbackfilesadded = 0;
 | 
        
           |  |  | 203 |         $userswithnewfeedback = array();
 | 
        
           |  |  | 204 |   | 
        
           |  |  | 205 |         // Unzipping a large zip file is memory intensive.
 | 
        
           |  |  | 206 |         raise_memory_limit(MEMORY_EXTRA);
 | 
        
           |  |  | 207 |   | 
        
           |  |  | 208 |         $packer = get_file_packer('application/zip');
 | 
        
           |  |  | 209 |         core_php_time_limit::raise(ASSIGNFEEDBACK_FILE_MAXFILEUNZIPTIME);
 | 
        
           |  |  | 210 |   | 
        
           |  |  | 211 |         return $packer->extract_to_storage($zipfile,
 | 
        
           |  |  | 212 |                                     $contextid,
 | 
        
           |  |  | 213 |                                     'assignfeedback_file',
 | 
        
           |  |  | 214 |                                     ASSIGNFEEDBACK_FILE_IMPORT_FILEAREA,
 | 
        
           |  |  | 215 |                                     $USER->id,
 | 
        
           |  |  | 216 |                                     'import');
 | 
        
           |  |  | 217 |   | 
        
           |  |  | 218 |     }
 | 
        
           |  |  | 219 |   | 
        
           |  |  | 220 |     /**
 | 
        
           |  |  | 221 |      * Get the list of files extracted from the uploaded zip
 | 
        
           |  |  | 222 |      *
 | 
        
           |  |  | 223 |      * @param int $contextid
 | 
        
           |  |  | 224 |      * @return array of stored_files
 | 
        
           |  |  | 225 |      */
 | 
        
           |  |  | 226 |     public function get_import_files($contextid) {
 | 
        
           |  |  | 227 |         global $USER;
 | 
        
           |  |  | 228 |   | 
        
           |  |  | 229 |         $fs = get_file_storage();
 | 
        
           |  |  | 230 |         $files = $fs->get_directory_files($contextid,
 | 
        
           |  |  | 231 |                                           'assignfeedback_file',
 | 
        
           |  |  | 232 |                                           ASSIGNFEEDBACK_FILE_IMPORT_FILEAREA,
 | 
        
           |  |  | 233 |                                           $USER->id,
 | 
        
           |  |  | 234 |                                           '/import/', true); // Get files recursive (all levels).
 | 
        
           |  |  | 235 |   | 
        
           |  |  | 236 |         $keys = array_keys($files);
 | 
        
           |  |  | 237 |   | 
        
           |  |  | 238 |         return $files;
 | 
        
           |  |  | 239 |     }
 | 
        
           |  |  | 240 |   | 
        
           |  |  | 241 |     /**
 | 
        
           |  |  | 242 |      * Returns a mapping from unique user / group ids in folder names to array of moodle users.
 | 
        
           |  |  | 243 |      *
 | 
        
           |  |  | 244 |      * @param assign $assignment  - The assignment instance
 | 
        
           |  |  | 245 |      * @return array the mapping.
 | 
        
           |  |  | 246 |      */
 | 
        
           |  |  | 247 |     public function get_participant_mapping(assign $assignment): array {
 | 
        
           |  |  | 248 |         $currentgroup = groups_get_activity_group($assignment->get_course_module(), true);
 | 
        
           |  |  | 249 |         $allusers = $assignment->list_participants($currentgroup, false);
 | 
        
           |  |  | 250 |         $participants = array();
 | 
        
           |  |  | 251 |         foreach ($allusers as $user) {
 | 
        
           |  |  | 252 |             if ($assignment->get_instance()->teamsubmission) {
 | 
        
           |  |  | 253 |                 $group = $assignment->get_submission_group($user->id);
 | 
        
           |  |  | 254 |                 if (!$group) {
 | 
        
           |  |  | 255 |                     continue;
 | 
        
           |  |  | 256 |                 }
 | 
        
           |  |  | 257 |                 if (!isset($participants[$group->id])) {
 | 
        
           |  |  | 258 |                     $participants[$group->id] = [];
 | 
        
           |  |  | 259 |                 }
 | 
        
           |  |  | 260 |                 $participants[$group->id][] = $user;
 | 
        
           |  |  | 261 |             } else {
 | 
        
           |  |  | 262 |                 $participants[$assignment->get_uniqueid_for_user($user->id)] = [$user];
 | 
        
           |  |  | 263 |             }
 | 
        
           |  |  | 264 |         }
 | 
        
           |  |  | 265 |         return $participants;
 | 
        
           |  |  | 266 |     }
 | 
        
           |  |  | 267 |   | 
        
           |  |  | 268 |     /**
 | 
        
           |  |  | 269 |      * Process an uploaded zip file
 | 
        
           |  |  | 270 |      *
 | 
        
           |  |  | 271 |      * @param assign $assignment - The assignment instance
 | 
        
           |  |  | 272 |      * @param assign_feedback_file $fileplugin - The file feedback plugin
 | 
        
           |  |  | 273 |      * @return string - The html response
 | 
        
           |  |  | 274 |      */
 | 
        
           |  |  | 275 |     public function import_zip_files($assignment, $fileplugin) {
 | 
        
           |  |  | 276 |         global $CFG, $PAGE, $DB;
 | 
        
           |  |  | 277 |   | 
        
           |  |  | 278 |         core_php_time_limit::raise(ASSIGNFEEDBACK_FILE_MAXFILEUNZIPTIME);
 | 
        
           |  |  | 279 |         $packer = get_file_packer('application/zip');
 | 
        
           |  |  | 280 |   | 
        
           |  |  | 281 |         $feedbackfilesupdated = 0;
 | 
        
           |  |  | 282 |         $feedbackfilesadded = 0;
 | 
        
           |  |  | 283 |         $userswithnewfeedback = array();
 | 
        
           |  |  | 284 |         $contextid = $assignment->get_context()->id;
 | 
        
           |  |  | 285 |   | 
        
           |  |  | 286 |         $fs = get_file_storage();
 | 
        
           |  |  | 287 |         $files = $this->get_import_files($contextid);
 | 
        
           |  |  | 288 |   | 
        
           |  |  | 289 |         $participants = $this->get_participant_mapping($assignment);
 | 
        
           |  |  | 290 |   | 
        
           |  |  | 291 |         foreach ($files as $unzippedfile) {
 | 
        
           |  |  | 292 |             $users = null;
 | 
        
           |  |  | 293 |             $plugin = null;
 | 
        
           |  |  | 294 |             $filename = '';
 | 
        
           |  |  | 295 |   | 
        
           |  |  | 296 |             if ($this->is_valid_filename_for_import($assignment, $unzippedfile, $participants, $users, $plugin, $filename)) {
 | 
        
           |  |  | 297 |                 if ($this->is_file_modified($assignment, $users, $plugin, $filename, $unzippedfile)) {
 | 
        
           |  |  | 298 |                     foreach ($users as $user) {
 | 
        
           |  |  | 299 |                         $grade = $assignment->get_user_grade($user->id, true);
 | 
        
           |  |  | 300 |   | 
        
           |  |  | 301 |                         // In 3.1 the default download structure of the submission files changed so that each student had their own
 | 
        
           |  |  | 302 |                         // separate folder, the files were not renamed and the folder structure was kept. It is possible that
 | 
        
           |  |  | 303 |                         // a user downloaded the submission files in 3.0 (or earlier) and edited the zip to add feedback or
 | 
        
           |  |  | 304 |                         // changed the behavior back to the previous format, the following code means that we will still support the
 | 
        
           |  |  | 305 |                         // old file structure. For more information please see - MDL-52489 / MDL-56022.
 | 
        
           |  |  | 306 |                         $path = pathinfo($filename);
 | 
        
           |  |  | 307 |                         if ($path['dirname'] == '.') { // Student submissions are not in separate folders.
 | 
        
           |  |  | 308 |                             $basename = $filename;
 | 
        
           |  |  | 309 |                             $dirname = "/";
 | 
        
           |  |  | 310 |                             $dirnamewslash = "/";
 | 
        
           |  |  | 311 |                         } else {
 | 
        
           |  |  | 312 |                             $basename = $path['basename'];
 | 
        
           |  |  | 313 |                             $dirname = $path['dirname'];
 | 
        
           |  |  | 314 |                             $dirnamewslash = $dirname . "/";
 | 
        
           |  |  | 315 |                         }
 | 
        
           |  |  | 316 |   | 
        
           |  |  | 317 |                         if ($oldfile = $fs->get_file($contextid,
 | 
        
           |  |  | 318 |                                                      'assignfeedback_file',
 | 
        
           |  |  | 319 |                                                      ASSIGNFEEDBACK_FILE_FILEAREA,
 | 
        
           |  |  | 320 |                                                      $grade->id,
 | 
        
           |  |  | 321 |                                                      $dirname,
 | 
        
           |  |  | 322 |                                                      $basename)) {
 | 
        
           |  |  | 323 |                             // Update existing feedback file.
 | 
        
           |  |  | 324 |                             $oldfile->replace_file_with($unzippedfile);
 | 
        
           |  |  | 325 |                             $feedbackfilesupdated++;
 | 
        
           |  |  | 326 |                         } else {
 | 
        
           |  |  | 327 |                             // Create a new feedback file.
 | 
        
           |  |  | 328 |                             $newfilerecord = new stdClass();
 | 
        
           |  |  | 329 |                             $newfilerecord->contextid = $contextid;
 | 
        
           |  |  | 330 |                             $newfilerecord->component = 'assignfeedback_file';
 | 
        
           |  |  | 331 |                             $newfilerecord->filearea = ASSIGNFEEDBACK_FILE_FILEAREA;
 | 
        
           |  |  | 332 |                             $newfilerecord->filename = $basename;
 | 
        
           |  |  | 333 |                             $newfilerecord->filepath = $dirnamewslash;
 | 
        
           |  |  | 334 |                             $newfilerecord->itemid = $grade->id;
 | 
        
           |  |  | 335 |                             $fs->create_file_from_storedfile($newfilerecord, $unzippedfile);
 | 
        
           |  |  | 336 |                             $feedbackfilesadded++;
 | 
        
           |  |  | 337 |                         }
 | 
        
           |  |  | 338 |                         $userswithnewfeedback[$user->id] = 1;
 | 
        
           |  |  | 339 |   | 
        
           |  |  | 340 |                         // Update the number of feedback files for this user.
 | 
        
           |  |  | 341 |                         $fileplugin->update_file_count($grade);
 | 
        
           |  |  | 342 |   | 
        
           |  |  | 343 |                         // Update the last modified time on the grade which will trigger student notifications.
 | 
        
           |  |  | 344 |                         $assignment->notify_grade_modified($grade);
 | 
        
           |  |  | 345 |                     }
 | 
        
           |  |  | 346 |                 }
 | 
        
           |  |  | 347 |             }
 | 
        
           |  |  | 348 |         }
 | 
        
           |  |  | 349 |   | 
        
           |  |  | 350 |         require_once($CFG->dirroot . '/mod/assign/feedback/file/renderable.php');
 | 
        
           |  |  | 351 |         $importsummary = new assignfeedback_file_import_summary($assignment->get_course_module()->id,
 | 
        
           |  |  | 352 |                                                             count($userswithnewfeedback),
 | 
        
           |  |  | 353 |                                                             $feedbackfilesadded,
 | 
        
           |  |  | 354 |                                                             $feedbackfilesupdated);
 | 
        
           |  |  | 355 |   | 
        
           |  |  | 356 |         $assignrenderer = $assignment->get_renderer();
 | 
        
           |  |  | 357 |         $renderer = $PAGE->get_renderer('assignfeedback_file');
 | 
        
           |  |  | 358 |   | 
        
           |  |  | 359 |         $o = '';
 | 
        
           |  |  | 360 |   | 
        
           |  |  | 361 |         $o .= $assignrenderer->render(new assign_header($assignment->get_instance(),
 | 
        
           |  |  | 362 |                                                         $assignment->get_context(),
 | 
        
           |  |  | 363 |                                                         false,
 | 
        
           |  |  | 364 |                                                         $assignment->get_course_module()->id,
 | 
        
           |  |  | 365 |                                                         get_string('uploadzipsummary', 'assignfeedback_file')));
 | 
        
           |  |  | 366 |   | 
        
           |  |  | 367 |         $o .= $renderer->render($importsummary);
 | 
        
           |  |  | 368 |   | 
        
           |  |  | 369 |         $o .= $assignrenderer->render_footer();
 | 
        
           |  |  | 370 |         return $o;
 | 
        
           |  |  | 371 |     }
 | 
        
           |  |  | 372 |   | 
        
           |  |  | 373 | }
 |