AutorÃa | Ultima modificación | Ver Log |
<?php// This file is part of local_downloadcenter for Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>./*** Download center plugin** @package local_downloadcenter* @author Simeon Naydenov (moniNaydenov@gmail.com)* @copyright 2020 Academic Moodle Cooperation {@link http://www.academic-moodle-cooperation.org}* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/defined('MOODLE_INTERNAL') || die();class local_downloadcenter_factory {/*** @var*/private $course;/*** @var*/private $user;/*** @var*/private $sortedresources;/*** @var*/private $filteredresources;private $_downloadoptions;/*** @var array*/private $availableresources = ['resource','folder','publication','page','book','lightboxgallery','assign','glossary','etherpadlite',];/*** @var array*/private $jsnames = [];/*** @var*/private $progress;/*** local_downloadcenter_factory constructor.* @param $course* @param $user*/public function __construct($course, $user) {$this->course = $course;$this->user = $user;$this->_downloadoptions = ['filesrealnames' => false,'addnumbering' => false,];}/*** @return array* @throws coding_exception* @throws dml_exception* @throws moodle_exception*/public function get_resources_for_user() {global $DB, $CFG;// Only downloadable resources should be shown!if (!empty($this->sortedresources)) {return $this->sortedresources;}$modinfo = get_fast_modinfo($this->course);$usesections = course_format_uses_sections($this->course->format);$sorted = [];if ($usesections) {$sections = $DB->get_records('course_sections', array('course' => $this->course->id), 'section');// Thanks to https://github.com/marinaglancy for the fix!$max = course_get_format($this->course)->get_format_options()['numsections'] ?? count($sections);$unnamedsections = [];$namedsections = [];foreach ($sections as $section) {if (intval($section->section) > $max) {break;}if (!isset($sorted[$section->section]) && $section->visible) {$sorted[$section->section] = new stdClass;$title = trim(get_section_name($this->course, $section->section));$title = self::shorten_filename($title);$sorted[$section->section]->title = $title;if (empty($title)) {$unnamedsections[] = $section->section;} else {$namedsections[$title] = true;}$sorted[$section->section]->res = []; // TODO: fix empty names here!!!}}foreach ($unnamedsections as $sectionid) {$untitled = get_string('untitled', 'local_downloadcenter');$title = $untitled;$i = 1;while (isset($namedsections[$title])) {$title = $untitled . ' ' . strval($i);$i++;}$namedsections[$title] = true;$sorted[$sectionid]->title = $title;}} else {$sorted['default'] = new stdClass;// TODO: fix here if needed!$sorted['default']->title = '0';$sorted['default']->res = [];}$cms = [];$resources = [];foreach ($modinfo->cms as $cm) {if (!in_array($cm->modname, $this->availableresources)) {continue;}if (!$cm->uservisible) {continue;}if (!$cm->has_view() && $cm->modname != 'folder') {// Exclude label and similar!continue;}$cms[$cm->id] = $cm;$resources[$cm->modname][] = $cm->instance;}// Preload instances!foreach ($resources as $modname => $instances) {$resources[$modname] = $DB->get_records_list($modname, 'id', $instances, 'id');}$availablesections = array_keys($sorted);$currentsection = '';foreach ($cms as $cm) {if (!isset($resources[$cm->modname][$cm->instance])) {continue;}$resource = $resources[$cm->modname][$cm->instance];if ($usesections) {if ($cm->sectionnum !== $currentsection) {$currentsection = $cm->sectionnum;}if (!in_array($currentsection, $availablesections)) {continue;}} else {$currentsection = 'default';}$cmcontext = context_module::instance($cm->id);if ($cm->modname == 'glossary') {if ( !has_capability('mod/glossary:manageentries', $cmcontext) && !$resource->allowprintview) {continue;}}if (!isset($this->jsnames[$cm->modname])) {$this->jsnames[$cm->modname] = get_string('modulenameplural', 'mod_' . $cm->modname);}$icon = '<img src="'.$cm->get_icon_url().'" class="activityicon" alt="'.$cm->get_module_type_name().'" /> ';// TODO: $cm->visible..$res = new stdClass;$res->icon = $icon;$res->cmid = $cm->id;$res->name = $cm->get_formatted_name();$res->modname = $cm->modname;$res->instanceid = $cm->instance;$res->resource = $resource;$res->cm = $cm;$res->context = $cmcontext;$sorted[$currentsection]->res[] = $res;}$this->sortedresources = $sorted;return $sorted;}/*** @return array*/public function get_js_modnames() {return array($this->jsnames);}/*** @return string* @throws coding_exception* @throws dml_exception*/public function create_zip() {global $DB, $CFG, $USER, $OUTPUT, $PAGE, $SITE;if (file_exists($CFG->dirroot . '/mod/publication/locallib.php')) {require_once($CFG->dirroot . '/mod/publication/locallib.php');} else {define('PUBLICATION_MODE_UPLOAD', 0);define('PUBLICATION_MODE_IMPORT', 1);}$modbookmissing = true;if (file_exists($CFG->dirroot . '/mod/book/tool/print/locallib.php')) {require_once($CFG->dirroot . '/mod/book/tool/print/locallib.php');$modbookmissing = false;}$bookrenderer = $PAGE->get_renderer('booktool_print');// Zip files and sent them to a user.$fs = get_file_storage();$filelist = [];$filteredresources = $this->filteredresources;// Needed for mod_publication!$userfields = \core_user\fields::for_userpic();$ufields = $userfields->get_sql('u', false, '', 'id', false)->selects;$useridentityfields = $CFG->showuseridentity != '' ? 'u.'.str_replace(', ', ', u.', $CFG->showuseridentity) . ', ' : '';$topicprefixid = 1;$topicscount = count($filteredresources);$topicprefixformat = '%0' . strlen($topicscount) . 'd';$filesrealnames = $this->_downloadoptions['filesrealnames'];$addnumbering = $this->_downloadoptions['addnumbering'];foreach ($filteredresources as $topicid => $info) {$info->title = html_entity_decode($info->title);$basedir = clean_filename($info->title);if ($addnumbering) {$basedir = sprintf($topicprefixformat, $topicprefixid) . '_' . $basedir;}$topicprefixid++;$basedir = self::shorten_filename($basedir);$filelist[$basedir] = null;$resprefixid = 1;$rescount = count($info->res);$resprefixformat = '%0' . strlen($rescount) . 'd';foreach ($info->res as $res) {$res->name = html_entity_decode($res->name);if ($addnumbering) {$res->name = sprintf($resprefixformat, $resprefixid) . '_' . $res->name;}$resdir = $basedir . '/' . self::shorten_filename(clean_filename($res->name));$filelist[$resdir] = null;$context = $res->context;if ($res->modname == 'resource') {$files = $fs->get_area_files($context->id, 'mod_resource', 'content', 0, 'sortorder DESC, id ASC', false);$file = array_shift($files); // Get only the first file - such are the requirements!if ($filesrealnames) {$realfilename = $file->get_filename();if ($addnumbering) {$realfilename = sprintf($resprefixformat, $resprefixid) . '_' . $realfilename;}$filename = $basedir . '/' . self::shorten_filename($realfilename);} else {$filename = $basedir . '/' . self::shorten_filename(clean_filename($res->name));}unset($filelist[$resdir]);$extension = mimeinfo_from_type('extension', $file->get_mimetype());$currentextension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));if (!empty($currentextension)) {$filename = mb_substr($filename, 0, -mb_strlen($currentextension) - 1);}$fullfilename = $filename . $extension;$filei = 1;while (isset($filelist[$fullfilename]) && $filei < 200) {$fullfilename = $filename . '_' . $filei . $extension;$filei++;}$filelist[$fullfilename] = $file;} else if ($res->modname == 'folder') {$folder = $fs->get_area_tree($context->id, 'mod_folder', 'content', 0);$this->add_folder_contents($filelist, $folder, $resdir);} else if ($res->modname == 'publication') {$cm = $res->cm;$conditions = [];$conditions['publication'] = $res->instanceid;$filesforzipping = [];$filearea = 'attachment';// Find out current groups mode.$groupmode = groups_get_activity_groupmode($cm);$currentgroup = groups_get_activity_group($cm, true);// Get group name for filename.$groupname = '';// Get all ppl that are allowed to submit assignments.list($esql, $params) = get_enrolled_sql($context, 'mod/publication:view', $currentgroup);$showall = false;if (has_capability('mod/publication:approve', $context) ||has_capability('mod/publication:grantextension', $context)) {$showall = true;}if ($showall) {$sql = 'SELECT u.id FROM {user} u '.'LEFT JOIN ('.$esql.') eu ON eu.id=u.id '.'WHERE u.deleted = 0 AND eu.id=u.id';} else {$sql = 'SELECT u.id FROM {user} u '.'LEFT JOIN ('.$esql.') eu ON eu.id=u.id '.'LEFT JOIN {publication_file} files ON (u.id = files.userid) '.'WHERE u.deleted = 0 AND eu.id=u.id '.'AND files.publication = '. $res->instanceid . ' ';if ($res->resource->mode == PUBLICATION_MODE_UPLOAD) {// Mode upload.// SN 11.07.2016 - feature #2738:// in mod/publication/locallib : line 81, publication::__construct() { ...// .....$this->instance->obtainteacherapproval = !$this->obtainteacherapproval ...// ..} ...// So flag has to be actually inverted!if (!$res->resource->obtainteacherapproval) {// Need teacher approval.$where = 'files.teacherapproval = 1';} else {// No need for teacher approval.// Teacher only hasnt rejected.$where = '(files.teacherapproval = 1 OR files.teacherapproval IS NULL)';}} else {// Mode import.if (!$res->resource->obtainstudentapproval) {// No need to ask student and teacher has approved.$where = 'files.teacherapproval = 1';} else {// Student and teacher have approved.$where = 'files.teacherapproval = 1 AND files.studentapproval = 1';}}$sql .= 'AND ' . $where . ' ';$sql .= 'GROUP BY u.id';}$users = $DB->get_records_sql($sql, $params);if (!empty($users)) {$users = array_keys($users);}// If groupmembersonly used, remove users who are not in any group.if ($users && !empty($CFG->enablegroupmembersonly) && $cm->groupmembersonly) {if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) {$users = array_intersect($users, array_keys($groupingusers));}}$userfields = [];foreach (\core_user\fields::get_name_fields() as $field) {$userfields[$field] = $field;}$userfields['id'] = 'id';$userfields['username'] = 'username';$userfields = implode(', ', $userfields);$viewfullnames = has_capability('moodle/site:viewfullnames', $context);// Get all files from each user.foreach ($users as $uploader) {$auserid = $uploader;$conditions['userid'] = $uploader;$records = $DB->get_records('publication_file', $conditions);// Get user firstname/lastname.$auser = $DB->get_record('user', array('id' => $auserid), $userfields);foreach ($records as $record) {$haspermission = false;if ($res->resource->mode == PUBLICATION_MODE_UPLOAD) {// Mode upload.// SN 11.07.2016 - feature #2738 - check comment above!if (!$res->resource->obtainteacherapproval) {// Need teacher approval.if ($record->teacherapproval == 1) {// Teacher has approved.$haspermission = true;}} else {// No need for teacher approval.if (is_null($record->teacherapproval) || $record->teacherapproval == 1) {// Teacher only hasnt rejected.$haspermission = true;}}} else {// Mode import.if (!$res->resource->obtainstudentapproval && $record->teacherapproval == 1) {// No need to ask student and teacher has approved.$haspermission = true;} else if ($res->resource->obtainstudentapproval &&$record->teacherapproval == 1 &&$record->studentapproval == 1) {// Student and teacher have approved.$haspermission = true;}}if (has_capability('mod/publication:approve', $context) || $haspermission) {// Is teacher or file is public.$file = $fs->get_file_by_id($record->fileid);// Get files new name.$fileext = strstr($file->get_filename(), '.');$fileoriginal = str_replace($fileext, '', $file->get_filename());$fileforzipname = clean_filename(($viewfullnames ? (fullname($auser) . '_') : '') .$fileoriginal.'_' . $auserid . $fileext);$fileforzipname = $resdir . '/' . self::shorten_filename($fileforzipname);// Save file name to array for zipping.$filelist[$fileforzipname] = $file;}}} // End of foreach.} else if ($res->modname == 'page') {$fsfiles = $fs->get_area_files($context->id,'mod_page','content');if (count($fsfiles) > 0) {foreach ($fsfiles as $file) {if ($file->get_filesize() == 0) {continue;}$filename = $resdir . '/data' . $file->get_filepath() . self::shorten_filename($file->get_filename());$filelist[$filename] = $file;}}if (count($fsfiles) == 0) {unset($filelist[$resdir]);$filename = $basedir . '/' . self::shorten_filename($res->name . '.html');} else {$filename = $resdir . '/' . self::shorten_filename($res->name . '.html');}$content = str_replace('@@PLUGINFILE@@', 'data', $res->resource->content);$content = self::convert_content_to_html_doc($res->name, $content);$filelist[$filename] = array($content); // Needs to be array to be saved as file.} else if ($res->modname == 'book' && !$modbookmissing) {$book = $res->resource;$cm = $res->cm;$chapters = book_preload_chapters($book);$fsfiles = $fs->get_area_files($context->id,'mod_book','chapter');if (count($fsfiles) > 0) {foreach ($fsfiles as $file) {if ($file->get_filesize() == 0) {continue;}$filename = $resdir . '/data' . $file->get_filepath() . self::shorten_filename($file->get_filename());$filelist[$filename] = $file;}}if (count($fsfiles) == 0) {unset($filelist[$resdir]);$filename = $basedir . '/' . self::shorten_filename($res->name . '.html');} else {$filename = $resdir . '/' . self::shorten_filename($res->name . '.html');}// Taken from mod/book/tool/print/index.php!$allchapters = $DB->get_records('book_chapters', array('bookid' => $book->id), 'pagenum');$book->intro = str_replace('@@PLUGINFILE@@', 'data', $book->intro);$content = '<a name="top"></a>';$content .= $OUTPUT->heading(format_string($book->name, true, array('context' => $context)), 1);$content .= '<p class="book_summary">' .format_text($book->intro, $book->introformat, array('noclean' => true, 'context' => $context)) .'</p>';$toc = $bookrenderer->render_print_book_toc($chapters, $book, $cm);$content .= $toc;// Chapters!$link1 = $CFG->wwwroot.'/mod/book/view.php?id='.$this->course->id.'&chapterid=';$link2 = $CFG->wwwroot.'/mod/book/view.php?id='.$this->course->id;foreach ($chapters as $ch) {$chapter = $allchapters[$ch->id];if ($chapter->hidden) {continue;}$content .= '<div class="book_chapter"><a name="ch'.$ch->id.'"></a>';$title = book_get_chapter_title($chapter->id, $chapters, $book, $context);if (!$book->customtitles) {if (!$chapter->subchapter) {$content .= $OUTPUT->heading($title);} else {$content .= $OUTPUT->heading($title, 3);}}$chaptercontent = str_replace($link1, '#ch', $chapter->content);$chaptercontent = str_replace($link2, '#top', $chaptercontent);$chaptercontent = str_replace('@@PLUGINFILE@@', 'data', $chaptercontent);$content .= format_text($chaptercontent,$chapter->contentformat,array('noclean' => true, 'context' => $context));$content .= '</div>';$content .= '<a href="#toc">↑ ' . get_string('top', 'mod_book') . '</a>';}$content = self::convert_content_to_html_doc($res->name, $content);$filelist[$filename] = array($content); // Needs to be array to be saved as file.} else if ($res->modname == 'lightboxgallery') {$fs = get_file_storage();$files = $fs->get_area_files($context->id, 'mod_lightboxgallery', 'gallery_images');foreach ($files as $storedfile) {if (!$storedfile->is_valid_image()) {continue;}$filename = $resdir . '/' . self::shorten_filename($storedfile->get_filename());$filelist[$filename] = $storedfile;}} else if ($res->modname == 'assign') {require_once($CFG->dirroot . '/mod/assign/locallib.php');require_once($CFG->dirroot . '/mod/assign/externallib.php');if ($res->resource->allowsubmissionsfromdate < time() || $res->resource->alwaysshowdescription) {$fsfiles = $fs->get_area_files($context->id, 'mod_assign', 'introattachment', 0, 'id', false);foreach ($fsfiles as $file) {if ($file->get_filesize() == 0) {continue;}$filename = $resdir . '/intro' . $file->get_filepath() . self::shorten_filename($file->get_filename());$filelist[$filename] = $file;}$fsfiles = $fs->get_area_files($context->id, 'mod_assign', 'intro', 0, 'id', false);foreach ($fsfiles as $file) {if ($file->get_filesize() == 0) {continue;}$filename = $resdir . '/intro/files' . $file->get_filepath() . self::shorten_filename($file->get_filename());$filelist[$filename] = $file;}$introtitle = get_string('description') . ' ' . $res->name;$introcontent = str_replace('@@PLUGINFILE@@', 'files', $res->resource->intro);$introcontent = self::convert_content_to_html_doc($introtitle, $introcontent);$filelist[$resdir . '/intro/intro.html'] = [$introcontent];}$submissionsstr = get_string('gradeitem:submissions', 'assign');$assign = new assign($context, null, null);$assignplugins = $assign->get_submission_plugins();$feedbackplugins = $assign->get_feedback_plugins();$params = ['assignment' => $res->instanceid];$isstudent = !has_capability('mod/assign:viewgrades', $context);if ($isstudent) {// When student, fetch only own submissions!$submissions = $assign->get_all_submissions($USER->id);} else {$submissions = $DB->get_records('assign_submission', $params, 'attemptnumber ASC');}foreach ($submissions as $submission) {$user = null;$group = null;if ($submission->userid != 0) {$user = $DB->get_record('user', ['id' => $submission->userid]);$fullname = $resdir. '/' . $submissionsstr . '/' . self::shorten_filename(fullname($user));} else if ($submission->groupid != 0) {$group = $DB->get_record('groups', ['id' => $submission->groupid]);$groupname = get_string('group', 'group') . ': ' . $group->name;$fullname = $resdir. '/' . $submissionsstr . '/' . self::shorten_filename($groupname);} else {$groupname = get_string('group', 'group') . ': ' . get_string('defaultteam', 'assign');$fullname = $resdir. '/' . $submissionsstr . '/' . self::shorten_filename($groupname);}// Submission!foreach ($assignplugins as $assignplugin) {if (!$assignplugin->is_enabled() || !$assignplugin->is_visible()) {continue;}// Subtype is 'assignsubmission', type is currently 'file' or 'onlinetext'.$component = $assignplugin->get_subtype().'_'.$assignplugin->get_type();$fileareas = $assignplugin->get_file_areas();foreach ($fileareas as $filearea => $name) {if ($areafiles = $fs->get_area_files($context->id, $component, $filearea, $submission->id, 'itemid, filepath, filename', false)) {foreach ($areafiles as $file) {$filename = $fullname . $file->get_filepath() . self::shorten_filename($file->get_filename());$filelist[$filename] = $file;}}}if ($assignplugin->get_type() == 'onlinetext') {$onlinetext = $assignplugin->get_editor_text('onlinetext', $submission->id);$onlinetext = str_replace('@@PLUGINFILE@@/', '', $onlinetext);if (mb_strlen(trim($onlinetext)) > 0) {$onlinetext = self::convert_content_to_html_doc($assignplugin->get_name(), $onlinetext);$filename = $fullname . '/' . self::shorten_filename($assignplugin->get_name() . '.html');$filelist[$filename] = [$onlinetext];}}}// Feedback!if (empty($user)) {if ($isstudent) {$user = $USER; // Applicable with group submissions!} else {continue; // There is no feedback per group AFAIK.}}$feedback = $assign->get_assign_feedback_status_renderable($user);// The feedback for our latest submission.if ($feedback && $feedback->grade) {$fullname .= '/' . get_string('feedback', 'grades');foreach ($feedbackplugins as $feedbackplugin) {if (!$feedbackplugin->is_enabled() || !$feedbackplugin->is_visible()) {continue;}$component = $feedbackplugin->get_subtype().'_'.$feedbackplugin->get_type();$fileareas = $feedbackplugin->get_file_areas();foreach ($fileareas as $filearea => $name) {if ($areafiles = $fs->get_area_files($context->id, $component, $filearea, $feedback->grade->id, 'itemid, filepath, filename', false)) {foreach ($areafiles as $file) {$filename = $fullname . $file->get_filepath() . self::shorten_filename($file->get_filename());$filelist[$filename] = $file;}}}if ($feedbackplugin->get_type() == 'comments') {$comments = $feedbackplugin->get_editor_text('comments', $feedback->grade->id);$comments = str_replace('@@PLUGINFILE@@/', '', $comments);if (mb_strlen(trim($comments)) > 0) {$comments = self::convert_content_to_html_doc($feedbackplugin->get_name(), $comments);$filename = $fullname . '/' . self::shorten_filename($feedbackplugin->get_name() . '.html');$filelist[$filename] = [$comments];}}}}}} else if ($res->modname == 'glossary') {$hook = 'ALL'; // Setting up default values as taken from mod/glossary/print.php!$pivotkey = 'concept';$fullpivot = false;$currentpivot = '';$mode = '';$fmtoptions = ['context' => $context];$glossary = $res->resource;$displayformat = $glossary->displayformat;$course = $this->course;$cm = $res->cm;$content = '';ob_start();$sitename = get_string("site") . ': <span class="strong">' . format_string($SITE->fullname) . '</span>';echo html_writer::tag('div', $sitename, array('class' => 'sitename'));$coursename = get_string("course") . ': <span class="strong">' . format_string($course->fullname) . ' ('. format_string($course->shortname) . ')</span>';echo html_writer::tag('div', $coursename, array('class' => 'coursename'));$modname = get_string("modulename", "glossary") . ': <span class="strong">' . format_string($glossary->name, true) . '</span>';echo html_writer::tag('div', $modname, array('class' => 'modname'));list($allentries, $count) = glossary_get_entries_by_letter($glossary, $context, 'ALL', 0, 0);if ( $allentries ) {foreach ($allentries as $entry) {$pivot = $entry->{$pivotkey};$upperpivot = core_text::strtoupper($pivot);$pivottoshow = core_text::strtoupper(format_string($pivot, true, $fmtoptions));// Reduce pivot to 1cc if necessary.if (!$fullpivot) {$upperpivot = core_text::substr($upperpivot, 0, 1);$pivottoshow = core_text::substr($pivottoshow, 0, 1);}// If there's a group break.if ($currentpivot != $upperpivot) {$currentpivot = $upperpivot;echo html_writer::tag('div', clean_text($pivottoshow), array('class' => 'mdl-align strong'));}glossary_print_entry($course, $cm, $glossary, $entry, $mode, $hook, 1, $displayformat, true);}// The all entries value may be a recordset or an array.if ($allentries instanceof moodle_recordset) {$allentries->close();}}$content .= ob_get_contents();ob_end_clean();$fileurl = $CFG->wwwroot . '/pluginfile.php/' . $context->id . '/mod_glossary/';$content = str_replace($fileurl, 'data/', $content);$filename = $resdir . '/' . self::shorten_filename($res->name . '.html');$linkrel = '<link href="css/styles.css" rel="stylesheet">';$linkrel .= '<style> .img-fluid { max-width: 100%; height: auto;}</style>';$content = '<div class="path-mod-glossary" id="#page-mod-glossary-print">' . $content . '</div>';$content = self::convert_content_to_html_doc($res->name, $content, $linkrel);$filelist[$filename] = [$content];$filelist[$resdir . '/css/styles.css'] = $CFG->dirroot . '/mod/glossary/styles.css';// Handle attachments.$fsfiles = $fs->get_area_files($context->id,'mod_glossary','attachment');if (count($fsfiles) > 0) {foreach ($fsfiles as $file) {if ($file->get_filesize() == 0) {continue;}$filename = $resdir . '/data/attachment/' . $file->get_itemid() . '/' . $file->get_filename();$filelist[$filename] = $file;}}// Handle entries.$fsfiles = $fs->get_area_files($context->id,'mod_glossary','entry');if (count($fsfiles) > 0) {foreach ($fsfiles as $file) {if ($file->get_filesize() == 0) {continue;}$filename = $resdir . '/data/entry/' . $file->get_itemid() . '/' . $file->get_filename();$filelist[$filename] = $file;}}} else if ($res->modname == 'etherpadlite') {require_once($CFG->dirroot . '/mod/etherpadlite/lib.php');$etherpadconfig = get_config('etherpadlite');$domain = $etherpadconfig->url;$padid = $res->resource->uri;$etherpadclient = \mod_etherpadlite\api\client::get_instance($etherpadconfig->apikey, $domain); // If not working, try $domain.'api' instead.// Handle groups here.$groupmode = groups_get_activity_groupmode($res->cm);if ($groupmode) {if ($groupmode == VISIBLEGROUPS || has_capability('moodle/course:managegroups', $res->context)) {$htmlcontent = $etherpadclient->get_html($padid);if (!empty($htmlcontent)) {$htmlcontent = self::append_etherpadlite_css($htmlcontent->html);$filename = $resdir . '/' . self::shorten_filename($res->name . '_' . get_string('allparticipants') . '.html');$filelist[$filename] = array($htmlcontent); // Needs to be array to be saved as file.}}$allgroups = groups_get_activity_allowed_groups($res->cm);foreach ($allgroups as $group) {$htmlcontent = $etherpadclient->get_html($padid . $group->id);if (!empty($htmlcontent)) {$htmlcontent = self::append_etherpadlite_css($htmlcontent->html);$filename = $resdir . '/' . self::shorten_filename($res->name . '_' . $group->name . '.html');$filelist[$filename] = array($htmlcontent); // Needs to be array to be saved as file.}}} else {$htmlcontent = $etherpadclient->get_html($padid);if (!empty($htmlcontent)) {$htmlcontent = self::append_etherpadlite_css($htmlcontent->html);$filename = $resdir . '/' . self::shorten_filename($res->name . '.html');$filelist[$filename] = array($htmlcontent); // Needs to be array to be saved as file.}}}$resprefixid++;}}\core\session\manager::write_close();$filename = sprintf('%s_%s.zip', $this->course->shortname, userdate(time(), '%Y%m%d_%H%M'));$zipwriter = \core_files\archive_writer::get_stream_writer($filename, \core_files\archive_writer::ZIP_WRITER);// Stream the files into the zip.foreach ($filelist as $pathinzip => $file) {if ($file instanceof \stored_file) {// Most of cases are \stored_file.$zipwriter->add_file_from_stored_file($pathinzip, $file);} else if (is_array($file)) {// Save $file as contents, from onlinetext subplugin.$content = reset($file);$zipwriter->add_file_from_string($pathinzip, $content);} else if (is_string($file)) {$zipwriter->add_file_from_filepath($pathinzip, $file);}}// Finish the archive.$zipwriter->finish();die;}/*** @param $filelist* @param $folder* @param $path*/private function add_folder_contents(&$filelist, $folder, $path) {if (!empty($folder['subdirs'])) {foreach ($folder['subdirs'] as $foldername => $subfolder) {$foldername = self::shorten_filename($foldername);$this->add_folder_contents($filelist, $subfolder, $path . '/' . $foldername);}}foreach ($folder['files'] as $filename => $file) {$filelist[$path . '/' . self::shorten_filename($filename)] = $file;}}/*** @param $data* @throws coding_exception* @throws dml_exception* @throws moodle_exception*/public function parse_form_data($data) {$data = (array)$data;$filtered = [];$sortedresources = $this->get_resources_for_user();$excludeempty = get_config('local_downloadcenter', 'exclude_empty_topics');foreach ($sortedresources as $sectionid => $info) {if (!isset($data['item_topic_' . $sectionid])) {continue;}$filtered[$sectionid] = new stdClass;$filtered[$sectionid]->title = $info->title;$filtered[$sectionid]->res = [];foreach ($info->res as $res) {$name = 'item_' . $res->modname . '_' . $res->instanceid;if (!isset($data[$name])) {continue;}$filtered[$sectionid]->res[] = $res;}if ($excludeempty && empty($filtered[$sectionid]->res)) {unset($filtered[$sectionid]);}}$this->filteredresources = $filtered;$this->_downloadoptions['filesrealnames'] = isset($data['filesrealnames']);$this->_downloadoptions['addnumbering'] = isset($data['addnumbering']);}/*** @param $filename* @param int $maxlength* @return string*/public static function shorten_filename($filename, $maxlength = 64) {$filename = (string)$filename;$filename = str_replace('/', '_', $filename);if (strlen($filename) <= $maxlength) {return $filename;}$limit = round($maxlength / 2) - 1;return substr($filename, 0, $limit) . '___' . substr($filename, (1 - $limit));}public static function convert_content_to_html_doc($title, $content, $additionalhead = '') {return <<<HTML<!doctype html><html><head><title>$title</title><meta charset="utf-8">$additionalhead</head><body>$content</body></html>HTML;}public static function append_etherpadlite_css($htmlcontent) {$csscontent = <<<CSS<style>ol {counter-reset: item;}ol > li {counter-increment: item;}ol ol > li {display: block;}ol > li {display: block;}ol > li:before {content: counters(item, ".") ". ";}ol ol > li:before {content: counters(item, ".") ". ";margin-left: -20px;}ul.indent {list-style-type: none;}</style></body>CSS;return str_replace('</body>', $csscontent, $htmlcontent);}}