ÿØÿà JFIF    ÿÛ „  ( %!1"%)+...383-7(-.+  -%%--------+------------/----------------------------ÿÀ  ¶" ÿÄ     ÿÄ @    !1AQaq‘¡"±ÁÑð2’BRráS‚ñ3b¢CT²Ò #cÿÄ    ÿÄ '   1!AQ2a"‘±#ÿÚ   ? ò(/p‘—–¢·,M|¯G»R£üešT. ôŸEoCFñ‡ 4ÔkåóxR|µÁ¨ÓDà!Ç´µ˜‡p ÍQ‹§!þž^õWsŒy  åÁ§$á«%ºq˜™JyyË0y«^Ϗ -3ÃÏËÈ£Æ\P’ä„s&•‹Üs üô'àWt¹pñCp$bÚF`·7.^)¾!)ÒÙ˜–ÅÏš^h¾ø³·ìe±ŒaeÖ—Í,e=B}Jéߦ$$½—šÙÜCC¯¶è8β–Åkèwx LÉngT±æ¹£Ócœ¿Í/©Éÿ ‰ÚCÒ­mq;Tt¶–}0"zÖPcd1š­¤tˆ„ÐÓâqú[™öUCŠ2޿د­É(¸ßúçšmW,Ò ºf‹Ån™ÄLêÁ8üÁkÁ€L¥ÍuJ1œôrÂSŒÓöt!7EUíïb)AËi¬â-ÙHk8òÁiXYwÅ)O^"ÇØriÛô{»wRUKÙÏÚlÓ¬€‚’שT ] ªb—ÊîKC^×M“xùäñz¬zJ× {4[¹M'IÆeH1LCWÕ]œûº WDæà°OÅ‚¹c²ÞuA–rL`HšpCez‡V’— Ž‚Ë„–ñ­'µR0ÕÖ=À:±G»C\nÆÉ5*¢ †3šhQ4ýÒi$Õ1"Ü]¢p-q3zcQ$ªö¨¥æf›‘»´ÝÚHá„e²JÇ–iÊ:·à¬Øc5Åk»Laª*wi [0Ówk ¦a¦0Õ²ÅÅ‚T¸’³q:Æ<¹ú Ò˜Æ}2VE•Ѐp¡Ô3Úº …h³^LJºçì¥Ánó|˜ÖˆÎˆ+« ¦dø‘Mº–d\ªDðÛ„Ì×LÝ——Ð9Ç|•FèçVm™¨€™3õS–9Äå¢<̉Ìm¢±`·º˜&Z²ž Ë®D«¶»6™‰©­HÈ Àá«h­i³04æ’hxœi3ï¨(ÓL·†‹¶ËpŒ ƒÜÒ? :õdsÀ –3æÓ·Üjâ¬9—]8n¼&]I F£¼…ì–—Œ0v°LǐÅfÛ2TÖ’aµ˜N@ÖBSÏ^à´4-±°b×nÈÈœÆD=KdŒø…ÄÈK,›ÖR§fjü$^ÔÎ!„6^ s:Üun\ôkCÞò÷<—Lúl Í›G¹ÀPá¼Nc¡šÒ…ÙWͳœ±vÊáЄ×9‹P‰cEØ‘™›µŸP<×g1 º©Ø¬wiÁ^l5× I/';Ë+´Z‡ÓÄFÕp[Èð’ HÄ ó 9¬Dl4“é±Ï”V=^Hð;žLädÉa‚°Ë,#/Ž~²BÔÛ QãñQtIeórVB,ÏÂf‹4#Μc‹É3ZIÖ Œ¢¥·üxa‡Ãçè„jŠ[5 Ä!U?,3žÎ×…ðdÓ÷háŠA‰ìÄ4÷ÃÜZÃE{‰®+W\ZÍE[‰»µk»MÝ­`¢©†˜ÃV‹-f¢¡†¢a«eŠ%«Y¨©q%jâd,Ôq`) ¤¦…šˆ ¦E>0Ùb²t–Ÿ  ÷jsςҒKÈcø(é›;k(’#ôŒQ ™C> õ³M9óºÆµ¤çâ;uÀ)5>RÔ¸fÓ~Ȧ—’-$fe«"FâUˆÊwµPÏu w+"åÉó¨6s™Û9(À¨ù©hE°½†n`m~“@©›p!Vkhµ Á1šbEqqÊ@ºèl›2 –Yã%‘‚hÛ{a¶‡ÅÞM²¬çL34®Çl]®‹ŽØŒm'RÜe35æöˆ­Á­ cP9šeÁköo´L³Ì=p8]”‡B¶,šº|ɏdzXˆØk*ÇÚ{#ñ‰pã(€¶‡9ý'šÜ³½¯kƒ†Â’ëSOƒ•Å®H6+a¢µˆ‹Y¨b˜b+XˆÖ!°u!¢"µˆˆn2ˆ Å0Ä`Å Ô®c(ÓÜGº•Ä»Œ âWî%q.áÐÄ÷î%umÍ£+ÜQ,Vn¦-GphU¸¢X­&,Gt ·K¢ÅÅ·¥RÄÊÉbKn N­R2g$VµÕó Qr#–ÓZUÏð0ÎtÙÀœz ëöo“Îk¯n„T°"SÞ+³/…€½"ižãO%Í%&Δâ‘ËØ´IˆÓ°Ë‰ÞM3.™yçÁzit›`4C`k¢¼á!álÄï sÂ[×!¤l¾æo"ƒIÔ'@ªu)3›ô®“@Z à¾] üœ'‡4¸PÞkÁ-qÄH‰ÓÍBd´ÿ —¹°ÄA&ÊUC„öz‚‚RæŠtf¬>˜ÑidšEçÑL÷áý¡V±h§­c¿¥¨ƒ@g¼…Ýö^ÞËc.ž„æ“I[ ª+·zÐÒÚ,½Ð»¶€C›7jk$๖€Ž¾ÅÙpp¶ÍþéΤ ½ØÎŒq ñpæžÅ¥#Øâ49ÃÂK^MYV“,¶Éz_òæ:…;Õ«¦I3âJ£¤û5$7Èxün\â]Êe¯(Ÿ&Ž‹¶2<6Ćf× æ¢ƱqWı[(ÙÂŽç‚T7¨@ÈÉÍß‚ïÙ"&3TYlGށ†)†#5ŠA©^T2ÆÁ†)©†©†¤yGXÁ†©"†)©¼ÅV WS†#©]R–r‹q5ÕbâWþBh¯u+ªÅÄ×ü„nÑ^êkªÁj‰jeœWˆÕÕ`µDµ2Ì+Ä µDµµ5Ô{¤Þ0RF’H÷AÛ<ÊÁ§ ƈæ0Ñ£ê4 öÚµ[¬/1²€â<-¬šö²r×0o×w ´xÐÒË„ g01¬„åEM蛇Ã\6µE›‘fÙO k÷CºnÓ1`iîÒ² áÂ!ÑLÄÿ ³¬\õ*:M=Ç»c‹2[‰ØsÕLò\ŒK L^™üÄN\¶#» Ç\……ßïIœÉ$¸ÎñÍ®ÔHÇ Ûí/´>Li”„†g^$ 7NÍÑÑ2M2ªNg=k½Ð}Ÿl6‡ —JWˆ”ÞéT·+µ¦üÂFè¢Vs6ýÆ4»2+2IÝ9ô9®ÇGÙÇ1+Ä8;*Õ§ž½D*îÑWÚçá3Ma¤·ˆ¥t}š²Ü…Q+Æüµ8HíS”üxGéÁˆ¦Ël„éÈ 5 µÄƒ6äÜ(kIš¯S†fÖ&¸®×v|Äyˆ*禌Éù@7-®Ä[]ÎÖ¿ê`º…=:…žJVnݳvðÖKE¼‚ »mà ÷f®:Ë ™–4rð¡4` ܹçž~‹C=œ…¾Ïj|VDtK.ƒ"9 Ï ­–éXá³6WÒïIL-Ї Ç PK<\=WAunoconv/db/install.phpnu[. defined('MOODLE_INTERNAL') || die(); /** * Installation for unoconv. * * @package fileconverter_unoconv * @copyright 2017 Andrew Nicols * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ function xmldb_fileconverter_unoconv_install() { global $CFG; $unoconvpresent = !empty($CFG->pathtounoconv); $unoconvpresent = $unoconvpresent && file_exists($CFG->pathtounoconv); $unoconvpresent = $unoconvpresent && !is_dir($CFG->pathtounoconv); $unoconvpresent = $unoconvpresent && file_is_executable($CFG->pathtounoconv); if ($unoconvpresent) { // Unoconv is currently configured correctly. // Enable it. $plugins = \core_plugin_manager::instance()->get_plugins_of_type('fileconverter'); $plugins['unoconv']->set_enabled(true); } } PK<\ ye> > )unoconv/lang/en/fileconverter_unoconv.phpnu[. /** * Strings for plugin 'fileconverter_unoconv' * * @package fileconverter_unoconv * @copyright 2017 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); $string['pathtounoconv'] = 'Path to unoconv document converter'; $string['pathtounoconv_help'] = 'Path to unoconv document converter. This is an executable that is capable of converting between document formats supported by LibreOffice. This is optional, but if specified, Moodle will use it to automatically convert between document formats. This is used to support a wider range of input files for the assignment annotate PDF feature.'; $string['pluginname'] = 'Unoconv'; $string['privacy:metadata'] = 'The Unoconv document converter plugin does not store any personal data.'; $string['test_unoconv'] = 'Test unoconv path'; $string['test_unoconvdoesnotexist'] = 'The unoconv path does not point to the unoconv program. Please review your path settings.'; $string['test_unoconvdownload'] = 'Download the converted pdf test file.'; $string['test_unoconvempty'] = 'The unoconv path is not set. Please review your path settings.'; $string['test_unoconvisdir'] = 'The unoconv path points to a folder, please include the unoconv program in the path you specify'; $string['test_unoconvnotestfile'] = 'The test document to be converted to PDF is missing.'; $string['test_unoconvnotexecutable'] = 'The unoconv path points to a file that is not executable'; $string['test_unoconvok'] = 'The unoconv path appears to be properly configured.'; $string['test_unoconvversionnotsupported'] = 'The version of unoconv you have installed is not supported.'; PK<\(munoconv/version.phpnu[. /** * Version details * * @package fileconverter_unoconv * @copyright 2017 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); $plugin->version = 2025041400; // The current plugin version (Date: YYYYMMDDXX). $plugin->requires = 2025040800; // Requires this Moodle version. $plugin->component = 'fileconverter_unoconv'; // Full name of the plugin (used for diagnostics). PK<\5  $unoconv/classes/privacy/provider.phpnu[. /** * Privacy provider implementation for fileconverter_unoconv. * * @package fileconverter_unoconv * @copyright 2018 Mihail Geshoski * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace fileconverter_unoconv\privacy; defined('MOODLE_INTERNAL') || die(); /** * Privacy provider implementation for fileconverter_unoconv. * * @copyright 2018 Mihail Geshoski * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class provider implements \core_privacy\local\metadata\null_provider { /** * Get the language string identifier with the component's language * file to explain why this plugin stores no data. * * @return string */ public static function get_reason(): string { return 'privacy:metadata'; } } PK<\7L5L5unoconv/classes/converter.phpnu[. /** * Class for converting files between different file formats using unoconv. * * @package fileconverter_unoconv * @copyright 2017 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace fileconverter_unoconv; defined('MOODLE_INTERNAL') || die(); require_once($CFG->libdir . '/filelib.php'); use stored_file; use \core_files\conversion; /** * Class for converting files between different formats using unoconv. * * @package fileconverter_unoconv * @copyright 2017 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class converter implements \core_files\converter_interface { /** No errors */ const UNOCONVPATH_OK = 'ok'; /** Not set */ const UNOCONVPATH_EMPTY = 'empty'; /** Does not exist */ const UNOCONVPATH_DOESNOTEXIST = 'doesnotexist'; /** Is a dir */ const UNOCONVPATH_ISDIR = 'isdir'; /** Not executable */ const UNOCONVPATH_NOTEXECUTABLE = 'notexecutable'; /** Test file missing */ const UNOCONVPATH_NOTESTFILE = 'notestfile'; /** Version not supported */ const UNOCONVPATH_VERSIONNOTSUPPORTED = 'versionnotsupported'; /** Any other error */ const UNOCONVPATH_ERROR = 'error'; /** * @var bool $requirementsmet Whether requirements have been met. */ protected static $requirementsmet = null; /** * @var array $formats The list of formats supported by unoconv. */ protected static $formats; /** * Convert a document to a new format and return a conversion object relating to the conversion in progress. * * @param conversion $conversion The file to be converted * @return $this */ public function start_document_conversion(\core_files\conversion $conversion) { global $CFG; if (!self::are_requirements_met()) { $conversion->set('status', conversion::STATUS_FAILED); error_log( "Unoconv conversion failed to verify the configuraton meets the minimum requirements. " . "Please check the unoconv installation configuration." ); return $this; } $file = $conversion->get_sourcefile(); $filepath = $file->get_filepath(); // Sanity check that the conversion is supported. $fromformat = pathinfo($file->get_filename(), PATHINFO_EXTENSION); if (!self::is_format_supported($fromformat)) { $conversion->set('status', conversion::STATUS_FAILED); error_log( "Unoconv conversion for '" . $filepath . "' found input '" . $fromformat . "' " . "file extension to convert from is not supported." ); return $this; } $format = $conversion->get('targetformat'); if (!self::is_format_supported($format)) { $conversion->set('status', conversion::STATUS_FAILED); error_log( "Unoconv conversion for '" . $filepath . "' found output '" . $format . "' " . "file extension to convert to is not supported." ); return $this; } // Copy the file to the tmp dir. $uniqdir = make_unique_writable_directory(make_temp_directory('core_file/conversions')); \core_shutdown_manager::register_function('remove_dir', array($uniqdir)); $localfilename = $file->get_id() . '.' . $fromformat; $filename = $uniqdir . '/' . $localfilename; try { // This function can either return false, or throw an exception so we need to handle both. if ($file->copy_content_to($filename) === false) { throw new \file_exception('storedfileproblem', 'Could not copy file contents to temp file.'); } } catch (\file_exception $fe) { error_log( "Unoconv conversion for '" . $filepath . "' encountered disk permission error when copying " . "submitted file contents to unique temp file: '" . $filename . "'." ); throw $fe; } // The temporary file to copy into. $newtmpfile = pathinfo($filename, PATHINFO_FILENAME) . '.' . $format; $newtmpfile = $uniqdir . '/' . clean_param($newtmpfile, PARAM_FILE); $cmd = escapeshellcmd(trim($CFG->pathtounoconv)) . ' ' . escapeshellarg('-f') . ' ' . escapeshellarg($format) . ' ' . escapeshellarg('-o') . ' ' . escapeshellarg($newtmpfile) . ' ' . escapeshellarg($filename); $output = null; $currentdir = getcwd(); chdir($uniqdir); $result = exec($cmd, $output, $returncode); chdir($currentdir); touch($newtmpfile); if ($returncode != 0) { $conversion->set('status', conversion::STATUS_FAILED); error_log( "Unoconv conversion for '" . $filepath . "' from '" . $fromformat . "' to '" . $format . "' " . "was unsuccessful; returned with exit status code (" . $returncode . "). Please check the unoconv " . "configuration and conversion file content / format." ); return $this; } if (!file_exists($newtmpfile)) { $conversion->set('status', conversion::STATUS_FAILED); error_log( "Unoconv conversion for '" . $filepath . "' from '" . $fromformat . "' to '" . $format . "' " . "was unsuccessful; the output file was not found in '" . $newtmpfile . "'. Please check the disk " . "permissions." ); return $this; } if (filesize($newtmpfile) === 0) { $conversion->set('status', conversion::STATUS_FAILED); error_log( "Unoconv conversion for '" . $filepath . "' from '" . $fromformat . "' to '" . $format . "' " . "was unsuccessful; the output file size has 0 bytes in '" . $newtmpfile . "'. Please check the " . "conversion file content / format with the command: [ " . $cmd . " ]" ); return $this; } $conversion ->store_destfile_from_path($newtmpfile) ->set('status', conversion::STATUS_COMPLETE) ->update(); return $this; } /** * Poll an existing conversion for status update. * * @param conversion $conversion The file to be converted * @return $this */ public function poll_conversion_status(conversion $conversion) { // Unoconv does not support asynchronous conversion. return $this; } /** * Generate and serve the test document. * * @return void */ public function serve_test_document() { global $CFG; require_once($CFG->libdir . '/filelib.php'); $format = 'pdf'; $filerecord = [ 'contextid' => \context_system::instance()->id, 'component' => 'test', 'filearea' => 'fileconverter_unoconv', 'itemid' => 0, 'filepath' => '/', 'filename' => 'unoconv_test.docx' ]; // Get the fixture doc file content and generate and stored_file object. $fs = get_file_storage(); $testdocx = $fs->get_file($filerecord['contextid'], $filerecord['component'], $filerecord['filearea'], $filerecord['itemid'], $filerecord['filepath'], $filerecord['filename']); if (!$testdocx) { $fixturefile = dirname(__DIR__) . '/tests/fixtures/unoconv-source.docx'; $testdocx = $fs->create_file_from_pathname($filerecord, $fixturefile); } $conversions = conversion::get_conversions_for_file($testdocx, $format); foreach ($conversions as $conversion) { if ($conversion->get('id')) { $conversion->delete(); } } $conversion = new conversion(0, (object) [ 'sourcefileid' => $testdocx->get_id(), 'targetformat' => $format, ]); $conversion->create(); // Convert the doc file to the target format and send it direct to the browser. $this->start_document_conversion($conversion); do { sleep(1); $this->poll_conversion_status($conversion); $status = $conversion->get('status'); } while ($status !== conversion::STATUS_COMPLETE && $status !== conversion::STATUS_FAILED); readfile_accel($conversion->get_destfile(), 'application/pdf', true); } /** * Whether the plugin is configured and requirements are met. * * @return bool */ public static function are_requirements_met() { if (self::$requirementsmet === null) { $requirementsmet = self::test_unoconv_path()->status === self::UNOCONVPATH_OK; $requirementsmet = $requirementsmet && self::is_minimum_version_met(); self::$requirementsmet = $requirementsmet; } return self::$requirementsmet; } /** * Whether the minimum version of unoconv has been met. * * @return bool */ protected static function is_minimum_version_met() { global $CFG; $currentversion = 0; $supportedversion = 0.7; $unoconvbin = \escapeshellarg($CFG->pathtounoconv); $command = "$unoconvbin --version"; exec($command, $output); // If the command execution returned some output, then get the unoconv version. if ($output) { foreach ($output as $response) { if (preg_match('/unoconv (\\d+\\.\\d+)/', $response, $matches)) { $currentversion = (float) $matches[1]; } } if ($currentversion < $supportedversion) { return false; } else { return true; } } return false; } /** * Whether the plugin is fully configured. * * @return \stdClass */ public static function test_unoconv_path() { global $CFG; $unoconvpath = $CFG->pathtounoconv; $ret = new \stdClass(); $ret->status = self::UNOCONVPATH_OK; $ret->message = null; if (empty($unoconvpath)) { $ret->status = self::UNOCONVPATH_EMPTY; return $ret; } if (!file_exists($unoconvpath)) { $ret->status = self::UNOCONVPATH_DOESNOTEXIST; return $ret; } if (is_dir($unoconvpath)) { $ret->status = self::UNOCONVPATH_ISDIR; return $ret; } if (!\file_is_executable($unoconvpath)) { $ret->status = self::UNOCONVPATH_NOTEXECUTABLE; return $ret; } if (!self::is_minimum_version_met()) { $ret->status = self::UNOCONVPATH_VERSIONNOTSUPPORTED; return $ret; } return $ret; } /** * Whether a file conversion can be completed using this converter. * * @param string $from The source type * @param string $to The destination type * @return bool */ public static function supports($from, $to) { return self::is_format_supported($from) && self::is_format_supported($to); } /** * Whether the specified file format is supported. * * @param string $format Whether conversions between this format and another are supported * @return bool */ protected static function is_format_supported($format) { $formats = self::fetch_supported_formats(); $format = trim(\core_text::strtolower($format)); return in_array($format, $formats); } /** * Fetch the list of supported file formats. * * @return array */ protected static function fetch_supported_formats() { global $CFG; if (!isset(self::$formats)) { // Ask unoconv for it's list of supported document formats. $cmd = escapeshellcmd(trim($CFG->pathtounoconv)) . ' --show'; $pipes = array(); $pipesspec = array(2 => array('pipe', 'w')); $proc = proc_open($cmd, $pipesspec, $pipes); $programoutput = stream_get_contents($pipes[2]); fclose($pipes[2]); proc_close($proc); $matches = array(); preg_match_all('/\[\.(.*)\]/', $programoutput, $matches); $formats = $matches[1]; self::$formats = array_unique($formats); } return self::$formats; } /** * A list of the supported conversions. * * @return string */ public function get_supported_conversions() { return implode(', ', self::fetch_supported_formats()); } } PK<\2 2 unoconv/testunoconv.phpnu[. /** * Test that unoconv is configured correctly * * @package fileconverter_unoconv * @copyright 2017 Andrew Nicols * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require(__DIR__ . '/../../../config.php'); require_once($CFG->libdir . '/filelib.php'); $sendpdf = optional_param('sendpdf', 0, PARAM_BOOL); $PAGE->set_url(new moodle_url('/files/converter/unoconv/testunoconv.php')); $PAGE->set_context(context_system::instance()); require_login(); require_capability('moodle/site:config', context_system::instance()); $strheading = get_string('test_unoconv', 'fileconverter_unoconv'); $PAGE->navbar->add(get_string('administrationsite')); $PAGE->navbar->add(get_string('plugins', 'admin')); $PAGE->navbar->add(get_string('assignmentplugins', 'mod_assign')); $PAGE->navbar->add(get_string('feedbackplugins', 'mod_assign')); $PAGE->navbar->add(get_string('pluginname', 'fileconverter_unoconv'), new moodle_url('/admin/settings.php', array('section' => 'fileconverterunoconv'))); $PAGE->navbar->add($strheading); $PAGE->set_heading($strheading); $PAGE->set_title($strheading); $converter = new \fileconverter_unoconv\converter(); if ($sendpdf) { require_sesskey(); $converter->serve_test_document(); die(); } $result = \fileconverter_unoconv\converter::test_unoconv_path(); switch ($result->status) { case \fileconverter_unoconv\converter::UNOCONVPATH_OK: $msg = $OUTPUT->notification(get_string('test_unoconvok', 'fileconverter_unoconv'), 'success'); $pdflink = new moodle_url($PAGE->url, array('sendpdf' => 1, 'sesskey' => sesskey())); $msg .= html_writer::link($pdflink, get_string('test_unoconvdownload', 'fileconverter_unoconv')); $msg .= html_writer::empty_tag('br'); break; default: $msg = $OUTPUT->notification(get_string("test_unoconv{$result->status}", 'fileconverter_unoconv'), 'warning'); break; } $returl = new moodle_url('/admin/settings.php', array('section' => 'fileconverterunoconv')); $msg .= $OUTPUT->continue_button($returl); echo $OUTPUT->header(); echo $OUTPUT->box($msg, 'generalbox'); echo $OUTPUT->footer(); PK<\9+9+*unoconv/tests/fixtures/unoconv-source.docxnu[PK!7f [Content_Types].xml (Tn0W?DV8H` XKnDU A*)Yăښl 1iJ/z,'nVK~ϲ)am j0HuT9bx<9X Q 8AO1~qk 6$N{9+P9Y vuGDoRwͳ Iʊ~8WZ"V0}>uQwHoPK!N _rels/.rels (JA a}7 "Hw"w̤ھ P^O֛;<aYՠ؛`GkxmPY[g Gΰino/<<1ⳆA$>"f3\ȾTI SWY ig@X6_]7~ fˉao.b*lIrj),l0%b 6iD_, |uZ^t٢yǯ;!Y,}{C/h>PK!dQ1word/_rels/document.xml.rels (j0{-;ȹ@$~ CR`Fh擴wo'U%):(x/vw q Hoo6h4CvDLek)lה86. U>0̀"S+a_݃(vuݕcT/ <@]+y~a#oF֩K=dĂބ U0^Ƌۻ*e<}M$:cQ(U|92Z,?l?Gȫl2+*7K㡳K0i`.M0<4a.CMpUG bpᓨLJ٣j4x! .jR%(ɹ &Fjk9PK!Pword/theme/theme1.xmlYOo6w toc'vuر-MniP@I}úama[إ4:lЯGRX^6؊>$ !)O^rC$y@/yH*񄴽)޵߻UDb`}"qۋJחX^)I`nEp)liV[]1M<OP6r=zgbIguSebORD۫qu gZo~ٺlAplxpT0+[}`jzAV2Fi@qv֬5\|ʜ̭NleXdsjcs7f W+Ն7`g ȘJj|h(KD- dXiJ؇(x$( :;˹! I_TS 1?E??ZBΪmU/?~xY'y5g&΋/ɋ>GMGeD3Vq%'#q$8K)fw9:ĵ x}rxwr:\TZaG*y8IjbRc|XŻǿI u3KGnD1NIBs RuK>V.EL+M2#'fi ~V vl{u8zH *:(W☕ ~JTe\O*tHGHY}KNP*ݾ˦TѼ9/#A7qZ$*c?qUnwN%Oi4 =3ڗP 1Pm \\9Mؓ2aD];Yt\[x]}Wr|]g- eW )6-rCSj id DЇAΜIqbJ#x꺃 6k#ASh&ʌt(Q%p%m&]caSl=X\P1Mh9MVdDAaVB[݈fJíP|8 քAV^f Hn- "d>znNJ ة>b&2vKyϼD:,AGm\nziÙ.uχYC6OMf3or$5NHT[XF64T,ќM0E)`#5XY`פ;%1U٥m;R>QD DcpU'&LE/pm%]8firS4d 7y\`JnίI R3U~7+׸#m qBiDi*L69mY&iHE=(K&N!V.KeLDĕ{D vEꦚdeNƟe(MN9ߜR6&3(a/DUz<{ˊYȳV)9Z[4^n5!J?Q3eBoCM m<.vpIYfZY_p[=al-Y}Nc͙ŋ4vfavl'SA8|*u{-ߟ0%M07%<ҍPK!R \:word/settings.xmlUr0}LṎi/q/:}hHdtj\^?1D^y!Jw3z0=m/wLccL{ u&f^LfH)bk`nIۏz_#usP ŐB톍J{FA@"R;5jpTD];kuBo :H% 5d d4}N[+N/D~ c&* A-Q-SLN¼/(QE* V ~)Q:R L*\;d곡JmB4ͣòLyFL'Q-tdLFQҫ6x'8'\ujy$?;(}jyHzX-sVh^{Tl~WnXSKrEwgJez\0/>w`!JPmhZ!닱LK_laIlT /qG%zo^~AyK130~-;+o1+Ц`™Oɮ2[zjv77va %X9laKtXb0?(tKo@Mt$w Ld5@2O? uo):95gW"`Ou OX.n|~hD 0iPpzDPK!R|word/fontTable.xml_o0ߗ;O*sqW,҄Pg+ 紇ˏ3" u;Bf#6a߫˘@o0Z$ ͦO*ΌvyMX\!PS M^fGv,x7N ˆahEލ,i=iҚT Ұy fv5(z\[%hK/:!p(Y*Vti~`% -[2v sZǒy~-[D4TZwMB9S4~TOQ_FGuM$C"1 5CDlGLd|g"Ɔm"Dp5O&X7'w78O7ڒPK!J؊word/webSettings.xmlj0 {at_0JHR(/\Gi d$m5lz_im>Q42 mA ?Ut~hePK!/GdocProps/core.xml (Mk0-+:PKKo4Y%#uwi]F;eone^pN{c~˿׏ٚz[~oOݗ|-DF$KoyؗBD@bN G:~U{EYt(T"~!#F hQ\ZL3egSMGl~v㘏Tjf]^m.b U zHf7bO8<tP ݩj')f  q@HFFG1}}L߷*⎶ł;|`_Mzͦ֓%LC'7r)cuP?: _j)˂N+Yx0_tGAE-W$s/WPK!6Bword/styles.xml[rH}ߪwǺؒ튒uZ'q"y#/! )W}{N9?>/}QFg[2pB 'ޑmʼn\ᇁ/2?~O'qA|MENcg!"~da \F|9"tҥ A7ڏ/*3kOkOa䮢Бq .}mo)s!"X]F7Qv]U$t"bnqqa4=H''\q`s={_!ƿ'`+6|cwvYdb`nf`wbhozcg!Fpf<@ȇ2{*у(0 $@ei!婮+ס i7&6b #/y r}\W2~%Yt4HgGT@ U/l\ARo(9d_p+B ,'F]&ڛ8lo\{6#6 UIOj:0g.jB%n>\U)VJuz}e3ͅ,y<5Hc 6؋'Ę7:uˍR\yNFFT0q-M?䣧mfٸ53-IzPyT$ mXhY=~qj@Z!><'A7GMò#3:ꛄW꭯j$TvvJMVg}U5sTTNPY2;BDݐ7&uC y`8H |*7 }&T%o ;;uMG8P2TGꆼ @ݐ7&uCnțԞA#o ɛĦT$o>ᆭ䍫7*yP)٤ *a&`#bȰ9AuCބ!oP7Mꆼ @ɻ;&`pj @lz0@E&a+ybM@a'JvvJjxNP ː7 5yq"ꆼ uCnțԞA#o ɛĦT$o7NvM@agD X !ofk&#UIS7M&'fțéE&ɛu΋kz ?@$ CeJ&|:%`!

My First Heading

My first paragraph.

PK<\6ŚH`` unoconv/tests/converter_test.phpnu[. namespace fileconverter_unoconv; /** * A set of tests for some of the unoconv functionality within Moodle. * * @package fileconverter_unoconv * @copyright 2016 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ final class converter_test extends \advanced_testcase { /** * Helper to skip tests which _require_ unoconv. */ protected function require_unoconv() { global $CFG; if (empty($CFG->pathtounoconv) || !file_is_executable(trim($CFG->pathtounoconv))) { // No conversions are possible, sorry. $this->markTestSkipped(); } } /** * Get a testable mock of the fileconverter_unoconv class. * * @param array $mockedmethods A list of methods you intend to override * If no methods are specified, only abstract functions are mocked. * @return \fileconverter_unoconv\converter */ protected function get_testable_mock($mockedmethods = []) { $converter = $this->getMockBuilder(\fileconverter_unoconv\converter::class) ->onlyMethods($mockedmethods) ->getMock(); return $converter; } /** * Tests for the start_document_conversion function. */ public function test_start_document_conversion(): void { $this->resetAfterTest(); $this->require_unoconv(); // Mock the file to be converted. $filerecord = [ 'contextid' => \context_system::instance()->id, 'component' => 'test', 'filearea' => 'unittest', 'itemid' => 0, 'filepath' => '/', 'filename' => 'test.docx', ]; $fs = get_file_storage(); $source = __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'unoconv-source.docx'; $testfile = $fs->create_file_from_pathname($filerecord, $source); $converter = $this->get_testable_mock(); $conversion = new \core_files\conversion(0, (object) [ 'targetformat' => 'pdf', ]); $conversion->set_sourcefile($testfile); $conversion->create(); // Convert the document. $converter->start_document_conversion($conversion); $result = $conversion->get_destfile(); $this->assertNotFalse($result); $this->assertSame('application/pdf', $result->get_mimetype()); $this->assertGreaterThan(0, $result->get_filesize()); } /** * Tests for the test_unoconv_path function. * * @dataProvider provider_test_unoconv_path * @param string $path The path to test * @param int $status The expected status */ public function test_test_unoconv_path($path, $status): void { global $CFG; $this->resetAfterTest(); // Set the current path. $CFG->pathtounoconv = $path; // Run the tests. $result = \fileconverter_unoconv\converter::test_unoconv_path(); $this->assertEquals($status, $result->status); } /** * Provider for test_unoconv_path. * * @return array */ public static function provider_test_unoconv_path(): array { return [ 'Empty path' => [ 'path' => null, 'status' => \fileconverter_unoconv\converter::UNOCONVPATH_EMPTY, ], 'Invalid file' => [ 'path' => '/path/to/nonexistent/file', 'status' => \fileconverter_unoconv\converter::UNOCONVPATH_DOESNOTEXIST, ], 'Directory' => [ 'path' => __DIR__, 'status' => \fileconverter_unoconv\converter::UNOCONVPATH_ISDIR, ], ]; } } PK<\MzySunoconv/settings.phpnu[. /** * Settings for unoconv. * * @package fileconverter_unoconv * @copyright 2017 Andrew Nicols * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); // Unoconv setting. $settings->add(new admin_setting_configexecutable('pathtounoconv', new lang_string('pathtounoconv', 'fileconverter_unoconv'), new lang_string('pathtounoconv_help', 'fileconverter_unoconv'), '/usr/bin/unoconv') ); $url = new moodle_url('/files/converter/unoconv/testunoconv.php'); $link = html_writer::link($url, get_string('test_unoconv', 'fileconverter_unoconv')); $settings->add(new admin_setting_heading('test_unoconv', '', $link)); PK<\\classes/privacy/provider.phpnu[. /** * Data provider. * * @package core_fileconverter * @copyright 2018 Frédéric Massart * @author Frédéric Massart * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace core_fileconverter\privacy; defined('MOODLE_INTERNAL') || die(); use context; use core_privacy\local\metadata\collection; use core_privacy\local\request\approved_contextlist; use core_privacy\local\request\userlist; use core_privacy\local\request\approved_userlist; /** * Data provider class. * * @package core_fileconverter * @copyright 2018 Frédéric Massart * @author Frédéric Massart * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class provider implements \core_privacy\local\metadata\provider, \core_privacy\local\request\core_userlist_provider, \core_privacy\local\request\subsystem\provider { /** * Returns metadata. * * @param collection $collection The initialised collection to add items to. * @return collection A listing of user data stored through this system. */ public static function get_metadata(collection $collection): collection { $collection->add_plugintype_link('fileconverter', [], 'privacy:metadata:plugintypefileconverter'); return $collection; } /** * Get the list of contexts that contain user information for the specified user. * * @param int $userid The user to search. * @return \contextlist $contextlist The contextlist containing the list of contexts used in this plugin. */ public static function get_contexts_for_userid(int $userid): \core_privacy\local\request\contextlist { // We cannot associate files with a particular user as it would require to know all the details about // the source file, which only the component owning it knows about. And, the 'usermodified' attribute // of the conversion class is not an identifier of data ownership, merely that this user was logged in // when the conversion was requested. As such, as the owning component should declare the source file, // and we can't make sense of 'usermodified', we will not be reporting anything here. Also note that // the clean up task will ensure that whenever a source file is delete, its conversions also are. return new \core_privacy\local\request\contextlist(); } /** * Get the list of users who have data within a context. * * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination. */ public static function get_users_in_context(userlist $userlist) { } /** * Export all user data for the specified user, in the specified contexts. * * @param approved_contextlist $contextlist The approved contexts to export information for. */ public static function export_user_data(approved_contextlist $contextlist) { } /** * Delete all data for all users in the specified context. * * @param context $context The specific context to delete data for. */ public static function delete_data_for_all_users_in_context(context $context) { } /** * Delete multiple users within a single context. * * @param approved_userlist $userlist The approved context and user information to delete information for. */ public static function delete_data_for_users(approved_userlist $userlist) { } /** * Delete all user data for the specified user, in the specified contexts. * * @param approved_contextlist $contextlist The approved contexts and user information to delete information for. */ public static function delete_data_for_user(approved_contextlist $contextlist) { } } PK<\>e$ 1googledrive/lang/en/fileconverter_googledrive.phpnu[. /** * Strings for plugin 'fileconverter_googledrive' * * @package fileconverter_googledrive * @copyright 2017 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); $string['pluginname'] = 'Google Drive'; $string['disabled'] = 'Disabled'; $string['issuer'] = 'OAuth 2 service'; $string['issuer_help'] = 'The OAuth 2 service used to access Google Drive.'; $string['privacy:metadata:fileconverter_googledrive:externalpurpose'] = 'This information is sent to Google Drive API in order the file to be converted to an alternative format. The file is temporarily kept on Google Drive and gets deleted after the conversion is done.'; $string['privacy:metadata:fileconverter_googledrive:filecontent'] = 'The content of the file.'; $string['privacy:metadata:fileconverter_googledrive:filemimetype'] = 'The MIME type of the file.'; $string['privacy:metadata:fileconverter_googledrive:params'] = 'The query parameters passed to Google Drive API.'; $string['test_converter'] = 'Test this converter is working properly.'; $string['test_conversion'] = 'Test document conversion'; $string['test_conversionready'] = 'This document converter is configured properly.'; $string['test_conversionnotready'] = 'This document converter is not configured properly.'; $string['test_issuerinvalid'] = 'The OAuth service in the document converter settings is set to an invalid value.'; $string['test_issuernotenabled'] = 'The OAuth service set in the document converter settings is not enabled.'; $string['test_issuernotconnected'] = 'The OAuth service set in the document converter settings does not have a system account connected.'; $string['test_issuernotset'] = 'The OAuth service needs to be set in the document converter settings.'; PK<\ googledrive/test.phpnu[. /** * Test that googledrive is configured correctly * * @package fileconverter_googledrive * @copyright 2017 Andrew Nicols * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require(__DIR__ . '/../../../config.php'); require_once($CFG->libdir . '/filelib.php'); $sendpdf = optional_param('sendpdf', 0, PARAM_BOOL); $PAGE->set_url(new moodle_url('/files/converter/googledrive/test.php')); $PAGE->set_context(context_system::instance()); require_login(); require_capability('moodle/site:config', context_system::instance()); $strheading = get_string('test_conversion', 'fileconverter_googledrive'); $PAGE->navbar->add(get_string('administrationsite')); $PAGE->navbar->add(get_string('plugins', 'admin')); $PAGE->navbar->add(get_string('pluginname', 'fileconverter_googledrive'), new moodle_url('/admin/settings.php', array('section' => 'fileconvertergoogledrive'))); $PAGE->navbar->add($strheading); $PAGE->set_heading($strheading); $PAGE->set_title($strheading); $converter = new \fileconverter_googledrive\converter(); if ($sendpdf) { require_sesskey(); $converter->serve_test_document(); die(); } $result = $converter->are_requirements_met(); if ($result) { $msg = $OUTPUT->notification(get_string('test_conversionready', 'fileconverter_googledrive'), 'success'); $pdflink = new moodle_url($PAGE->url, array('sendpdf' => 1, 'sesskey' => sesskey())); $msg .= html_writer::link($pdflink, get_string('test_conversion', 'fileconverter_googledrive')); $msg .= html_writer::empty_tag('br'); } else { // Diagnostics time. $issuerid = get_config('fileconverter_googledrive', 'issuerid'); $msg = ''; if (empty($issuerid)) { $msg = $OUTPUT->notification(get_string('test_issuernotset', 'fileconverter_googledrive'), 'warning'); } if (empty($msg)) { $issuer = \core\oauth2\api::get_issuer($issuerid); if (empty($issuer)) { $msg = $OUTPUT->notification(get_string('test_issuerinvalid', 'fileconverter_googledrive'), 'warning'); } } if (empty($msg)) { if (!$issuer->get('enabled')) { $msg = $OUTPUT->notification(get_string('test_issuernotenabled', 'fileconverter_googledrive'), 'warning'); } } if (empty($msg)) { if (!$issuer->is_system_account_connected()) { $msg = $OUTPUT->notification(get_string('test_issuernotconnected', 'fileconverter_googledrive'), 'warning'); } } if (empty($msg)) { $msg = $OUTPUT->notification(get_string('test_conversionnotready', 'fileconverter_googledrive'), 'warning'); } } $returl = new moodle_url('/admin/settings.php', array('section' => 'fileconvertergoogledrive')); $msg .= $OUTPUT->continue_button($returl); echo $OUTPUT->header(); echo $OUTPUT->box($msg, 'generalbox'); echo $OUTPUT->footer(); PK<\׋XXgoogledrive/lib.phpnu[. /** * This plugin is used to convert documents with google drive. * * @package fileconverter_googledrive * @copyright 2017 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); require_once($CFG->libdir . '/google/lib.php'); /** * Callback to get the required scopes for system account. * * @param \core\oauth2\issuer $issuer * @return string */ function fileconverter_googledrive_oauth2_system_scopes(\core\oauth2\issuer $issuer) { if ($issuer->get('id') == get_config('fileconverter_googledrive', 'issuerid')) { return Google_Service_Drive::DRIVE_FILE; } return ''; } PK<\>@googledrive/version.phpnu[. /** * Version details * * @package fileconverter_googledrive * @copyright 2017 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); $plugin->version = 2025041400; // The current plugin version (Date: YYYYMMDDXX). $plugin->requires = 2025040800; // Requires this Moodle version. $plugin->component = 'fileconverter_googledrive'; // Full name of the plugin (used for diagnostics). PK<\#(googledrive/classes/privacy/provider.phpnu[. /** * Privacy class for requesting user data. * * @package fileconverter_googledrive * @copyright 2018 Mihail Geshoski * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace fileconverter_googledrive\privacy; defined('MOODLE_INTERNAL') || die(); use \core_privacy\local\metadata\collection; use \core_privacy\local\request\contextlist; use \core_privacy\local\request\approved_contextlist; use \core_privacy\local\request\userlist; use \core_privacy\local\request\approved_userlist; /** * Privacy class for requesting user data. * * @package fileconverter_googledrive * @copyright 2018 Mihail Geshoski * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class provider implements \core_privacy\local\metadata\provider, \core_privacy\local\request\core_userlist_provider, \core_privacy\local\request\plugin\provider { /** * Returns meta data about this system. * * @param collection $collection The initialised collection to add items to. * @return collection A listing of user data stored through this system. */ public static function get_metadata(collection $collection): collection { $collection->add_external_location_link('googledrive', [ 'params' => 'privacy:metadata:fileconverter_googledrive:params', 'filecontent' => 'privacy:metadata:fileconverter_googledrive:filecontent', 'filemimetype' => 'privacy:metadata:fileconverter_googledrive:filemimetype', ], 'privacy:metadata:fileconverter_googledrive:externalpurpose'); return $collection; } /** * Get the list of contexts that contain user information for the specified user. * * @param int $userid The user to search. * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin. */ public static function get_contexts_for_userid(int $userid): contextlist { $contextlist = new contextlist(); return $contextlist; } /** * Get the list of users who have data within a context. * * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination. */ public static function get_users_in_context(userlist $userlist) { } /** * Export all user data for the specified user, in the specified contexts. * * @param approved_contextlist $contextlist The approved contexts to export information for. */ public static function export_user_data(approved_contextlist $contextlist) { } /** * Delete all use data which matches the specified deletion_criteria. * * @param \context $context A user context. */ public static function delete_data_for_all_users_in_context(\context $context) { } /** * Delete multiple users within a single context. * * @param approved_userlist $userlist The approved context and user information to delete information for. */ public static function delete_data_for_users(approved_userlist $userlist) { } /** * Delete all user data for the specified user, in the specified contexts. * * @param approved_contextlist $contextlist The approved contexts and user information to delete information for. */ public static function delete_data_for_user(approved_contextlist $contextlist) { } } PK<\_{#{#!googledrive/classes/converter.phpnu[. /** * Class for converting files between different file formats using google drive. * * @package fileconverter_googledrive * @copyright 2017 Andrew Nicols * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace fileconverter_googledrive; defined('MOODLE_INTERNAL') || die(); use stored_file; use moodle_exception; use moodle_url; use \core_files\conversion; /** * Class for converting files between different formats using unoconv. * * @package fileconverter_googledrive * @copyright 2017 Andrew Nicols * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class converter implements \core_files\converter_interface { /** @var array $imports List of supported import file formats */ private static $imports = [ 'doc' => 'application/vnd.google-apps.document', 'docx' => 'application/vnd.google-apps.document', 'rtf' => 'application/vnd.google-apps.document', 'xls' => 'application/vnd.google-apps.spreadsheet', 'xlsx' => 'application/vnd.google-apps.spreadsheet', 'ppt' => 'application/vnd.google-apps.presentation', 'pptx' => 'application/vnd.google-apps.presentation', 'html' => 'application/vnd.google-apps.document' ]; /** @var array $export List of supported export file formats */ private static $exports = [ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'rtf' => 'application/rtf', 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'pdf' => 'application/pdf', 'txt' => 'text/plain' ]; /** * Convert a document to a new format and return a conversion object relating to the conversion in progress. * * @param \core_files\conversion $conversion The file to be converted * @return this */ public function start_document_conversion(\core_files\conversion $conversion) { global $CFG; $file = $conversion->get_sourcefile(); $format = $conversion->get('targetformat'); $issuerid = get_config('fileconverter_googledrive', 'issuerid'); if (empty($issuerid)) { $conversion->set('status', conversion::STATUS_FAILED); return $this; } $issuer = \core\oauth2\api::get_issuer($issuerid); if (empty($issuer)) { $conversion->set('status', conversion::STATUS_FAILED); return $this; } $client = \core\oauth2\api::get_system_oauth_client($issuer); $service = new \fileconverter_googledrive\rest($client); $contenthash = $file->get_contenthash(); $originalname = $file->get_filename(); if (strpos($originalname, '.') === false) { $conversion->set('status', conversion::STATUS_FAILED); return $this; } $importextension = substr($originalname, strrpos($originalname, '.') + 1); $importformat = self::$imports[$importextension]; $exportformat = self::$exports[$format]; $metadata = [ 'name' => $contenthash, 'mimeType' => $importformat ]; $filecontent = $file->get_content(); $filesize = $file->get_filesize(); $filemimetype = $file->get_mimetype(); // Start resumable upload. // First create empty file. $params = [ 'uploadType' => 'resumable', 'fields' => 'id,name' ]; $client->setHeader('X-Upload-Content-Type: ' . $filemimetype); $client->setHeader('X-Upload-Content-Length: ' . $filesize); $headers = $service->call('upload', $params, json_encode($metadata)); $uploadurl; // Google returns a location header with the location for the upload. foreach ($headers as $header) { if (stripos($header, 'Location:') === 0) { $uploadurl = trim(substr($header, strpos($header, ':') + 1)); } } if (empty($uploadurl)) { $conversion->set('status', conversion::STATUS_FAILED); return $this; } $params = [ 'uploadurl' => $uploadurl ]; $result = $service->call('upload_content', $params, $filecontent, $filemimetype); $fileid = $result->id; // Now export it again. $params = ['mimeType' => $exportformat]; $sourceurl = new moodle_url('https://www.googleapis.com/drive/v3/files/' . $fileid . '/export', $params); $source = $sourceurl->out(false); $tmp = make_request_directory(); $downloadto = $tmp . '/' . $fileid . '.' . $format; $options = ['filepath' => $downloadto, 'timeout' => 15, 'followlocation' => true, 'maxredirs' => 5]; $success = $client->download_one($source, null, $options); if ($success) { $conversion->store_destfile_from_path($downloadto); $conversion->set('status', conversion::STATUS_COMPLETE); $conversion->update(); } else { $conversion->set('status', conversion::STATUS_FAILED); } // Cleanup. $params = [ 'fileid' => $fileid ]; $service->call('delete', $params); return $this; } /** * Generate and serve the test document. * * @return stored_file */ public function serve_test_document() { global $CFG; require_once($CFG->libdir . '/filelib.php'); $filerecord = [ 'contextid' => \context_system::instance()->id, 'component' => 'test', 'filearea' => 'fileconverter_googledrive', 'itemid' => 0, 'filepath' => '/', 'filename' => 'conversion_test.docx' ]; // Get the fixture doc file content and generate and stored_file object. $fs = get_file_storage(); $testdocx = $fs->get_file($filerecord['contextid'], $filerecord['component'], $filerecord['filearea'], $filerecord['itemid'], $filerecord['filepath'], $filerecord['filename']); if (!$testdocx) { $fixturefile = dirname(__DIR__) . '/tests/fixtures/source.docx'; $testdocx = $fs->create_file_from_pathname($filerecord, $fixturefile); } $conversion = new \core_files\conversion(0, (object) [ 'targetformat' => 'pdf', ]); $conversion->set_sourcefile($testdocx); $conversion->create(); // Convert the doc file to pdf and send it direct to the browser. $this->start_document_conversion($conversion); $testfile = $conversion->get_destfile(); readfile_accel($testfile, 'application/pdf', true); } /** * Poll an existing conversion for status update. * * @param conversion $conversion The file to be converted * @return $this; */ public function poll_conversion_status(conversion $conversion) { return $this; } /** * Whether the plugin is configured and requirements are met. * * @return bool */ public static function are_requirements_met() { $issuerid = get_config('fileconverter_googledrive', 'issuerid'); if (empty($issuerid)) { return false; } $issuer = \core\oauth2\api::get_issuer($issuerid); if (empty($issuer)) { return false; } if (!$issuer->get('enabled')) { return false; } if (!$issuer->is_system_account_connected()) { return false; } return true; } /** * Whether a file conversion can be completed using this converter. * * @param string $from The source type * @param string $to The destination type * @return bool */ public static function supports($from, $to): bool { return isset(self::$imports[$from]) && isset(self::$exports[$to]); } /** * A list of the supported conversions. * * @return string */ public function get_supported_conversions() { return implode(', ', ['rtf', 'doc', 'xls', 'docx', 'xlsx', 'ppt', 'pptx', 'pdf', 'html']); } } PK<\Y  googledrive/classes/rest.phpnu[. /** * Google Drive Rest API. * * @package fileconverter_googledrive * @copyright 2017 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace fileconverter_googledrive; defined('MOODLE_INTERNAL') || die(); /** * Google Drive Rest API. * * @copyright 2017 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class rest extends \core\oauth2\rest { /** * Define the functions of the rest API. * * @return array Example: * [ 'listFiles' => [ 'method' => 'get', 'endpoint' => 'http://...', 'args' => [ 'folder' => PARAM_STRING ] ] ] */ public function get_api_functions() { return [ 'upload' => [ 'endpoint' => 'https://www.googleapis.com/upload/drive/v3/files', 'method' => 'post', 'args' => [ 'uploadType' => PARAM_RAW, 'fields' => PARAM_RAW ], 'response' => 'headers' ], 'upload_content' => [ 'endpoint' => '{uploadurl}', 'method' => 'put', 'args' => [ 'uploadurl' => PARAM_URL ], 'response' => 'json' ], 'create' => [ 'endpoint' => 'https://www.googleapis.com/drive/v3/files', 'method' => 'post', 'args' => [ 'fields' => PARAM_RAW ], 'response' => 'json' ], 'delete' => [ 'endpoint' => 'https://www.googleapis.com/drive/v3/files/{fileid}', 'method' => 'delete', 'args' => [ 'fileid' => PARAM_RAW ], 'response' => 'json' ], ]; } } PK<\9+9+&googledrive/tests/fixtures/source.docxnu[PK!7f [Content_Types].xml (Tn0W?DV8H` XKnDU A*)Yăښl 1iJ/z,'nVK~ϲ)am j0HuT9bx<9X Q 8AO1~qk 6$N{9+P9Y vuGDoRwͳ Iʊ~8WZ"V0}>uQwHoPK!N _rels/.rels (JA a}7 "Hw"w̤ھ P^O֛;<aYՠ؛`GkxmPY[g Gΰino/<<1ⳆA$>"f3\ȾTI SWY ig@X6_]7~ fˉao.b*lIrj),l0%b 6iD_, |uZ^t٢yǯ;!Y,}{C/h>PK!dQ1word/_rels/document.xml.rels (j0{-;ȹ@$~ CR`Fh擴wo'U%):(x/vw q Hoo6h4CvDLek)lה86. U>0̀"S+a_݃(vuݕcT/ <@]+y~a#oF֩K=dĂބ U0^Ƌۻ*e<}M$:cQ(U|92Z,?l?Gȫl2+*7K㡳K0i`.M0<4a.CMpUG bpᓨLJ٣j4x! .jR%(ɹ &Fjk9PK!Pword/theme/theme1.xmlYOo6w toc'vuر-MniP@I}úama[إ4:lЯGRX^6؊>$ !)O^rC$y@/yH*񄴽)޵߻UDb`}"qۋJחX^)I`nEp)liV[]1M<OP6r=zgbIguSebORD۫qu gZo~ٺlAplxpT0+[}`jzAV2Fi@qv֬5\|ʜ̭NleXdsjcs7f W+Ն7`g ȘJj|h(KD- dXiJ؇(x$( :;˹! I_TS 1?E??ZBΪmU/?~xY'y5g&΋/ɋ>GMGeD3Vq%'#q$8K)fw9:ĵ x}rxwr:\TZaG*y8IjbRc|XŻǿI u3KGnD1NIBs RuK>V.EL+M2#'fi ~V vl{u8zH *:(W☕ ~JTe\O*tHGHY}KNP*ݾ˦TѼ9/#A7qZ$*c?qUnwN%Oi4 =3ڗP 1Pm \\9Mؓ2aD];Yt\[x]}Wr|]g- eW )6-rCSj id DЇAΜIqbJ#x꺃 6k#ASh&ʌt(Q%p%m&]caSl=X\P1Mh9MVdDAaVB[݈fJíP|8 քAV^f Hn- "d>znNJ ة>b&2vKyϼD:,AGm\nziÙ.uχYC6OMf3or$5NHT[XF64T,ќM0E)`#5XY`פ;%1U٥m;R>QD DcpU'&LE/pm%]8firS4d 7y\`JnίI R3U~7+׸#m qBiDi*L69mY&iHE=(K&N!V.KeLDĕ{D vEꦚdeNƟe(MN9ߜR6&3(a/DUz<{ˊYȳV)9Z[4^n5!J?Q3eBoCM m<.vpIYfZY_p[=al-Y}Nc͙ŋ4vfavl'SA8|*u{-ߟ0%M07%<ҍPK!R \:word/settings.xmlUr0}LṎi/q/:}hHdtj\^?1D^y!Jw3z0=m/wLccL{ u&f^LfH)bk`nIۏz_#usP ŐB톍J{FA@"R;5jpTD];kuBo :H% 5d d4}N[+N/D~ c&* A-Q-SLN¼/(QE* V ~)Q:R L*\;d곡JmB4ͣòLyFL'Q-tdLFQҫ6x'8'\ujy$?;(}jyHzX-sVh^{Tl~WnXSKrEwgJez\0/>w`!JPmhZ!닱LK_laIlT /qG%zo^~AyK130~-;+o1+Ц`™Oɮ2[zjv77va %X9laKtXb0?(tKo@Mt$w Ld5@2O? uo):95gW"`Ou OX.n|~hD 0iPpzDPK!R|word/fontTable.xml_o0ߗ;O*sqW,҄Pg+ 紇ˏ3" u;Bf#6a߫˘@o0Z$ ͦO*ΌvyMX\!PS M^fGv,x7N ˆahEލ,i=iҚT Ұy fv5(z\[%hK/:!p(Y*Vti~`% -[2v sZǒy~-[D4TZwMB9S4~TOQ_FGuM$C"1 5CDlGLd|g"Ɔm"Dp5O&X7'w78O7ڒPK!J؊word/webSettings.xmlj0 {at_0JHR(/\Gi d$m5lz_im>Q42 mA ?Ut~hePK!/GdocProps/core.xml (Mk0-+:PKKo4Y%#uwi]F;eone^pN{c~˿׏ٚz[~oOݗ|-DF$KoyؗBD@bN G:~U{EYt(T"~!#F hQ\ZL3egSMGl~v㘏Tjf]^m.b U zHf7bO8<tP ݩj')f  q@HFFG1}}L߷*⎶ł;|`_Mzͦ֓%LC'7r)cuP?: _j)˂N+Yx0_tGAE-W$s/WPK!6Bword/styles.xml[rH}ߪwǺؒ튒uZ'q"y#/! )W}{N9?>/}QFg[2pB 'ޑmʼn\ᇁ/2?~O'qA|MENcg!"~da \F|9"tҥ A7ڏ/*3kOkOa䮢Бq .}mo)s!"X]F7Qv]U$t"bnqqa4=H''\q`s={_!ƿ'`+6|cwvYdb`nf`wbhozcg!Fpf<@ȇ2{*у(0 $@ei!婮+ס i7&6b #/y r}\W2~%Yt4HgGT@ U/l\ARo(9d_p+B ,'F]&ڛ8lo\{6#6 UIOj:0g.jB%n>\U)VJuz}e3ͅ,y<5Hc 6؋'Ę7:uˍR\yNFFT0q-M?䣧mfٸ53-IzPyT$ mXhY=~qj@Z!><'A7GMò#3:ꛄW꭯j$TvvJMVg}U5sTTNPY2;BDݐ7&uC y`8H |*7 }&T%o ;;uMG8P2TGꆼ @ݐ7&uCnțԞA#o ɛĦT$o>ᆭ䍫7*yP)٤ *a&`#bȰ9AuCބ!oP7Mꆼ @ɻ;&`pj @lz0@E&a+ybM@a'JvvJjxNP ː7 5yq"ꆼ uCnțԞA#o ɛĦT$o7NvM@agD X !ofk&#UIS7M&'fțéE&ɛu΋kz ?@$ CeJ&|:%`!. /** * Base class for unit tests for fileconverter_googledrive. * * @package fileconverter_googledrive * @copyright 2018 Mihail Geshoski * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace fileconverter_googledrive\privacy; defined('MOODLE_INTERNAL') || die(); use core_privacy\tests\provider_testcase; /** * Unit tests for files/converter/googledrive/classes/privacy/provider.php * * @copyright 2018 Mihail Geshoski * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ final class provider_test extends provider_testcase { /** * Test getting the context for the user ID related to this plugin. */ public function test_get_contexts_for_userid(): void { $this->resetAfterTest(); $user = $this->getDataGenerator()->create_user(); $contextlist = \fileconverter_googledrive\privacy\provider::get_contexts_for_userid($user->id); $this->assertEmpty($contextlist); } } PK<\CUUgoogledrive/settings.phpnu[. /** * Link to the OAuth 2 service we will use. * * @package fileconverter_googledrive * @copyright 2017 Andrew Nicols * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); if ($hassiteconfig) { $options = []; $issuers = \core\oauth2\api::get_all_issuers(); $options[''] = get_string('disabled', 'fileconverter_googledrive'); foreach ($issuers as $issuer) { $options[$issuer->get('id')] = s($issuer->get('name')); } $settings->add(new admin_setting_configselect('fileconverter_googledrive/issuerid', get_string('issuer', 'fileconverter_googledrive'), get_string('issuer_help', 'fileconverter_googledrive'), '', $options)); $url = new moodle_url('/files/converter/googledrive/test.php'); $link = html_writer::link($url, get_string('test_converter', 'fileconverter_googledrive')); $settings->add(new admin_setting_heading('test_converter', '', $link)); } PK<\=WAunoconv/db/install.phpnu[PK<\ ye> > )=unoconv/lang/en/fileconverter_unoconv.phpnu[PK<\(munoconv/version.phpnu[PK<\5  $unoconv/classes/privacy/provider.phpnu[PK<\7L5L5unoconv/classes/converter.phpnu[PK<\2 2 Punoconv/testunoconv.phpnu[PK<\9+9+*\unoconv/tests/fixtures/unoconv-source.docxnu[PK<\yxhh*unoconv/tests/fixtures/unoconv-source.htmlnu[PK<\6ŚH`` funoconv/tests/converter_test.phpnu[PK<\MzySunoconv/settings.phpnu[PK<\\ޟclasses/privacy/provider.phpnu[PK<\>e$ 1googledrive/lang/en/fileconverter_googledrive.phpnu[PK<\  googledrive/test.phpnu[PK<\׋XXDgoogledrive/lib.phpnu[PK<\>@googledrive/version.phpnu[PK<\#(googledrive/classes/privacy/provider.phpnu[PK<\_{#{#!googledrive/classes/converter.phpnu[PK<\Y  h googledrive/classes/rest.phpnu[PK<\9+9+&googledrive/tests/fixtures/source.docxnu[PK<\{+[?googledrive/tests/privacy/provider_test.phpnu[PK<\CUUmFgoogledrive/settings.phpnu[PK N