ÿØÿà 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-Ї Ç db/install.php000064400000001743152266407540007330 0ustar00. function xmldb_repository_upload_install() { global $CFG; $result = true; require_once($CFG->dirroot.'/repository/lib.php'); $upload_plugin = new repository_type('upload', array(), true); if (!$id = $upload_plugin->create(true)) { $result = false; } return $result; } db/access.php000064400000002223152266407540007115 0ustar00. /** * Plugin capabilities. * * @package repository_upload * @copyright 2009 Dongsheng Cai * @author Dongsheng Cai * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); $capabilities = array( 'repository/upload:view' => array( 'captype' => 'read', 'contextlevel' => CONTEXT_MODULE, 'archetypes' => array( 'user' => CAP_ALLOW ) ) ); lang/en/repository_upload.php000064400000003723152266407540012403 0ustar00. /** * Strings for component 'repository_upload', language 'en', branch 'MOODLE_20_STABLE' * * @package repository_upload * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ $string['configplugin'] = 'Configuration for upload plugin'; $string['pluginname_help'] = 'Upload a file to Moodle'; $string['pluginname'] = 'Upload a file'; $string['upload:view'] = 'Use uploading in file picker'; $string['upload_error_ini_size'] = 'The file is larger than the maximum size allowed.'; $string['upload_error_form_size'] = 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.'; $string['upload_error_partial'] = 'The uploaded file was only partially uploaded.'; $string['upload_error_no_file'] = 'No file was uploaded.'; $string['upload_error_no_tmp_dir'] = 'PHP is missing a temporary folder.'; $string['upload_error_cant_write'] = 'Failed to write file to disk.'; $string['upload_error_extension'] = 'A PHP extension stopped the file upload.'; $string['upload_error_invalid_file'] = 'The file \'{$a}\' is either empty or a folder. To upload folders zip them first.'; $string['privacy:metadata'] = 'The Upload a file repository plugin does not store or transmit any personal data.'; pix/icon.png000064400000003273152266407540007022 0ustar00PNG  IHDR szzIDATxUtd堻bW&ѰIضm۶m۶=8Aw^Vzj{չg}νǿ6E7&n$=$ĻHJtxG0sjкuR^8YeB,Gߐ3ٷ]a8;=wZߕ@Kur{Ci˪ɒ,T dȲI?;±dG '}w!PYzVjJ݅N*/fmYS"@8G"٠bhԃx8n fۜ#s&[=5q9'GL?VSu IšmFhZ̵G&J¤o(M&>ʻyd͵ܺ 7Xg qh4x _ #*6@"ȉDvmŋ!aL?61Db aW(P`͆q-p߆M{wx7>po=MU^!5͙3Ͼ eldʐ$ h$a)"]u56IJ8rpHK`Sr癳fYh-㶧-`2 sHJI 184ColW 3{аy r6 ;x0î ecx5^]X$o @"ٳ`ʕ())ZދĶչ˟?لp14Ǻ7G|ส8Fxq FFF%K#j*IT6(HV2ۥAb FaxąDqn*]` ~̙3fM{vP~FNC:bǢ8c&ڮ~lW[Nec)/n@cM>hG{*0F8묳Xł!BhDǑHply5rc`h M٨Cǖ(5`EG~ ~ff&*9(s΅ACF@Ct$ێ_`QK%VIOh@mBgg' ;`QŹ@L&2,3w }߈?n(RtJghd``PUUUZۗh(ўK.UɐZc2 ^yF ΂wjλqvXulT16о;Cwa@qq1\.^/֧c<,7[x2dT:`l?6\c$TF__X!w<@cŌ_~I=M?%据!7jO7``ΆYe!Mxx_ӉrplٴF_yOiҥ`NkH;KMeE:'T_&"MODn۔)SaV/_'隚| vE{]Iɗ]v٥BRADa_@GrS{FIENDB`lib.php000064400000031650152266407540006043 0ustar00. /** * This plugin is used to upload files * * @since Moodle 2.0 * @package repository_upload * @copyright 2010 Dongsheng Cai {@link http://dongsheng.org} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); require_once($CFG->dirroot . '/repository/lib.php'); /** * A repository plugin to allow user uploading files * * @since Moodle 2.0 * @package repository_upload * @copyright 2009 Dongsheng Cai {@link http://dongsheng.org} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class repository_upload extends repository { private $mimetypes = array(); /** * Print a upload form * @return array */ public function print_login() { return $this->get_listing(); } /** * Process uploaded file * @return array|bool */ public function upload($saveasfilename, $maxbytes) { global $CFG; $types = optional_param_array('accepted_types', '*', PARAM_RAW); $savepath = optional_param('savepath', '/', PARAM_PATH); $itemid = optional_param('itemid', 0, PARAM_INT); $license = optional_param('license', $CFG->sitedefaultlicense, PARAM_TEXT); $author = optional_param('author', '', PARAM_TEXT); $areamaxbytes = optional_param('areamaxbytes', FILE_AREA_MAX_BYTES_UNLIMITED, PARAM_INT); $overwriteexisting = optional_param('overwrite', false, PARAM_BOOL); return $this->process_upload($saveasfilename, $maxbytes, $types, $savepath, $itemid, $license, $author, $overwriteexisting, $areamaxbytes); } /** * Do the actual processing of the uploaded file * @param string $saveasfilename name to give to the file * @param int $maxbytes maximum file size * @param mixed $types optional array of file extensions that are allowed or '*' for all * @param string $savepath optional path to save the file to * @param int $itemid optional the ID for this item within the file area * @param string $license optional the license to use for this file * @param string $author optional the name of the author of this file * @param bool $overwriteexisting optional user has asked to overwrite the existing file * @param int $areamaxbytes maximum size of the file area. * @return array containing details of the file uploaded */ public function process_upload($saveasfilename, $maxbytes, $types = '*', $savepath = '/', $itemid = 0, $license = null, $author = '', $overwriteexisting = false, $areamaxbytes = FILE_AREA_MAX_BYTES_UNLIMITED) { global $USER, $CFG; \core\session\manager::write_close(); if ((is_array($types) and in_array('*', $types)) or $types == '*') { $this->mimetypes = '*'; } else { foreach ($types as $type) { $this->mimetypes[] = mimeinfo('type', $type); } } if ($license == null) { $license = $CFG->sitedefaultlicense; } $record = new stdClass(); $record->filearea = 'draft'; $record->component = 'user'; $record->filepath = $savepath; $record->itemid = $itemid; $record->license = $license; $record->author = $author; $context = context_user::instance($USER->id); $elname = 'repo_upload_file'; $fs = get_file_storage(); $sm = get_string_manager(); if ($record->filepath !== '/') { $record->filepath = file_correct_filepath($record->filepath); } if (!isset($_FILES[$elname])) { throw new moodle_exception('nofile'); } if (!empty($_FILES[$elname]['error'])) { switch ($_FILES[$elname]['error']) { case UPLOAD_ERR_INI_SIZE: throw new moodle_exception('upload_error_ini_size', 'repository_upload'); break; case UPLOAD_ERR_FORM_SIZE: throw new moodle_exception('upload_error_form_size', 'repository_upload'); break; case UPLOAD_ERR_PARTIAL: throw new moodle_exception('upload_error_partial', 'repository_upload'); break; case UPLOAD_ERR_NO_FILE: throw new moodle_exception('upload_error_no_file', 'repository_upload'); break; case UPLOAD_ERR_NO_TMP_DIR: throw new moodle_exception('upload_error_no_tmp_dir', 'repository_upload'); break; case UPLOAD_ERR_CANT_WRITE: throw new moodle_exception('upload_error_cant_write', 'repository_upload'); break; case UPLOAD_ERR_EXTENSION: throw new moodle_exception('upload_error_extension', 'repository_upload'); break; default: throw new moodle_exception('nofile'); } } $avscanstarttime = microtime(true); \core\antivirus\manager::scan_file($_FILES[$elname]['tmp_name'], $_FILES[$elname]['name'], true); $avscantime = microtime(true) - $avscanstarttime; // {@link repository::build_source_field()} $sourcefield = $this->get_file_source_info($_FILES[$elname]['name']); $record->source = self::build_source_field($sourcefield); if (empty($saveasfilename)) { $record->filename = clean_param($_FILES[$elname]['name'], PARAM_FILE); } else { $ext = ''; $match = array(); $filename = clean_param($_FILES[$elname]['name'], PARAM_FILE); if (strpos($filename, '.') === false) { // File has no extension at all - do not add a dot. $record->filename = $saveasfilename; } else { if (preg_match('/\.([a-z0-9]+)$/i', $filename, $match)) { if (isset($match[1])) { $ext = $match[1]; } } $ext = !empty($ext) ? $ext : ''; if (preg_match('#\.(' . $ext . ')$#i', $saveasfilename)) { // The saveas filename contains file extension already. $record->filename = $saveasfilename; } else { $record->filename = $saveasfilename . '.' . $ext; } } } // Check the file has some non-null contents - usually an indication that a user has // tried to upload a folder by mistake. if (!$this->check_valid_contents($_FILES[$elname]['tmp_name'])) { throw new moodle_exception('upload_error_invalid_file', 'repository_upload', '', $record->filename); } if ($this->mimetypes != '*') { // Check filetype. $filemimetype = file_storage::mimetype($_FILES[$elname]['tmp_name'], $record->filename); if (!in_array($filemimetype, $this->mimetypes)) { throw new moodle_exception('invalidfiletype', 'repository', '', get_mimetype_description(array('filename' => $_FILES[$elname]['name']))); } } if (empty($record->itemid)) { $record->itemid = 0; } $filesize = filesize($_FILES[$elname]['tmp_name']); if (($maxbytes !== -1) && ($filesize > $maxbytes)) { $maxbytesdisplay = display_size($maxbytes, 0); throw new file_exception('maxbytesfile', (object) array('file' => $record->filename, 'size' => $maxbytesdisplay)); } if (file_is_draft_area_limit_reached($record->itemid, $areamaxbytes, $filesize)) { throw new file_exception('maxareabytes'); } // Ensure the user does not upload too many draft files in a short period. if (file_is_draft_areas_limit_reached($USER->id)) { throw new file_exception('maxdraftitemids'); } $record->contextid = $context->id; $record->userid = $USER->id; if (repository::draftfile_exists($record->itemid, $record->filepath, $record->filename)) { $existingfilename = $record->filename; $unusedfilename = repository::get_unused_filename($record->itemid, $record->filepath, $record->filename); $record->filename = $unusedfilename; $storedfile = $fs->create_file_from_pathname($record, $_FILES[$elname]['tmp_name']); if ($overwriteexisting) { repository::overwrite_existing_draftfile($record->itemid, $record->filepath, $existingfilename, $record->filepath, $record->filename); $record->filename = $existingfilename; } else { $event = array(); $event['event'] = 'fileexists'; $event['newfile'] = new stdClass; $event['newfile']->filepath = $record->filepath; $event['newfile']->filename = $unusedfilename; $event['newfile']->url = moodle_url::make_draftfile_url($record->itemid, $record->filepath, $unusedfilename)->out(false); $event['existingfile'] = new stdClass; $event['existingfile']->filepath = $record->filepath; $event['existingfile']->filename = $existingfilename; $event['existingfile']->url = moodle_url::make_draftfile_url($record->itemid, $record->filepath, $existingfilename)->out(false); return $event; } } else { $storedfile = $fs->create_file_from_pathname($record, $_FILES[$elname]['tmp_name']); } $logevent = \core\event\draft_file_added::create([ 'objectid' => $storedfile->get_id(), 'context' => $context, 'other' => [ 'itemid' => $record->itemid, 'filename' => $record->filename, 'filesize' => $filesize, 'filepath' => $record->filepath, 'contenthash' => $storedfile->get_contenthash(), 'avscantime' => $avscantime, ], ]); $logevent->trigger(); return array( 'url' => moodle_url::make_draftfile_url($record->itemid, $record->filepath, $record->filename)->out(false), 'id' => $record->itemid, 'file' => $record->filename); } /** * Checks the contents of the given file is not completely NULL - this can happen if a * user drags & drops a folder onto a filemanager / filepicker element * @param string $filepath full path (including filename) to file to check * @return true if file has at least one non-null byte within it */ protected function check_valid_contents($filepath) { $buffersize = 4096; $fp = fopen($filepath, 'r'); if (!$fp) { return false; // Cannot read the file - something has gone wrong. } while (!feof($fp)) { // Read the file 4k at a time. $data = fread($fp, $buffersize); if (preg_match('/[^\0]+/', $data)) { fclose($fp); return true; // Return as soon as a non-null byte is found. } } // Entire file is NULL. fclose($fp); return false; } /** * Return a upload form * @return array */ public function get_listing($path = '', $page = '') { global $CFG; $ret = array(); $ret['nologin'] = true; $ret['nosearch'] = true; $ret['norefresh'] = true; $ret['list'] = array(); $ret['dynload'] = false; $ret['upload'] = array('label' => get_string('attachment', 'repository'), 'id' => 'repo-form'); $ret['allowcaching'] = true; // Indicates that result of get_listing() can be cached in filepicker.js. return $ret; } /** * supported return types * @return int */ public function supported_returntypes() { return FILE_INTERNAL; } /** * Is this repository accessing private data? * * @return bool */ public function contains_private_data() { return false; } } version.php000064400000002304152266407540006754 0ustar00. /** * Version details * * @package repository * @subpackage upload * @copyright 2009 Dongsheng Cai * @author Dongsheng Cai * @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 = 'repository_upload'; // Full name of the plugin (used for diagnostics) classes/privacy/provider.php000064400000002764152266407540012245 0ustar00. /** * Privacy Subsystem implementation for repository_upload. * * @package repository_upload * @copyright 2018 Zig Tan * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace repository_upload\privacy; defined('MOODLE_INTERNAL') || die(); /** * Privacy Subsystem for repository_upload implementing null_provider. * * @copyright 2018 Zig Tan * @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'; } } tests/generator/lib.php000064400000002252152266407540011167 0ustar00. /** * Upload repository data generator * * @package repository_upload * @category test * @copyright 2013 Frédéric Massart * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ /** * Upload repository data generator class * * @package repository_upload * @category test * @copyright 2013 Frédéric Massart * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class repository_upload_generator extends testing_repository_generator { } tests/behat/upload_file.feature000064400000002750152266407540012650 0ustar00@repository @repository_upload @_file_upload Feature: Upload files In order to add contents As a user I need to upload files @javascript Scenario: Upload a file in a multiple file filemanager Given the following "courses" exist: | fullname | shortname | category | | Course 1 | C1 | 0 | And I log in as "admin" And I turn editing mode on And I add the "Private files" block if not present When I follow "Manage private files..." And I upload "lib/tests/fixtures/empty.txt" file to "Files" filemanager Then I should see "1" elements in "Files" filemanager And I should see "empty.txt" in the "div.fp-content" "css_element" And I upload "lib/tests/fixtures/empty.txt" file to "Files" filemanager as: | Save as | empty_copy.txt | Then I should see "2" elements in "Files" filemanager And I should see "empty.txt" And I should see "empty_copy.txt" @javascript Scenario: Verify logs for file upload Given I am on the "My private files" page logged in as "admin" And I upload "lib/tests/fixtures/empty.txt" file to "Files" filemanager And I click on "Save changes" "button" And I am on the "System logs report" page And I click on "Get these logs" "button" Then I should see "The user with id '2' has uploaded file '/empty.txt' to the draft file area with item id" in the "File added to draft area" "table_row" And I should see "Size: 32 bytes. Content hash: " in the "File added to draft area" "table_row" tests/behat/behat_repository_upload.php000064400000023052152266407540014445 0ustar00. /** * Steps definitions for the upload repository type. * * @package repository_upload * @category test * @copyright 2013 David Monllaó * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ // NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php. require_once(__DIR__ . '/../../../../lib/behat/core_behat_file_helper.php'); use Behat\Mink\Exception\DriverException as DriverException, Behat\Mink\Exception\ExpectationException as ExpectationException, Behat\Gherkin\Node\TableNode as TableNode; /** * Steps definitions to deal with the upload repository. * * @package repository_upload * @category test * @copyright 2013 David Monllaó * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class behat_repository_upload extends behat_base { use core_behat_file_helper; /** * Uploads a file to the specified filemanager leaving other fields in upload form default. The paths should be relative to moodle codebase. * * @When /^I upload "(?P(?:[^"]|\\")*)" file to "(?P(?:[^"]|\\")*)" filemanager$/ * @throws DriverException * @throws ExpectationException Thrown by behat_base::find * @param string $filepath * @param string $filemanagerelement */ public function i_upload_file_to_filemanager($filepath, $filemanagerelement) { $this->upload_file_to_filemanager($filepath, $filemanagerelement, new TableNode(array()), false); } /** * Uploads a file to the specified filemanager leaving other fields in upload form default and confirms to overwrite an existing file. The paths should be relative to moodle codebase. * * @When /^I upload and overwrite "(?P(?:[^"]|\\")*)" file to "(?P(?:[^"]|\\")*)" filemanager$/ * @throws DriverException * @throws ExpectationException Thrown by behat_base::find * @param string $filepath * @param string $filemanagerelement */ public function i_upload_and_overwrite_file_to_filemanager($filepath, $filemanagerelement) { $this->upload_file_to_filemanager($filepath, $filemanagerelement, new TableNode(array()), get_string('overwrite', 'repository')); } /** * Uploads a file to the specified filemanager and confirms to overwrite an existing file. The paths should be relative to moodle codebase. * * @When /^I upload "(?P(?:[^"]|\\")*)" file to "(?P(?:[^"]|\\")*)" filemanager as:$/ * @throws DriverException * @throws ExpectationException Thrown by behat_base::find * @param string $filepath * @param string $filemanagerelement * @param TableNode $data Data to fill in upload form */ public function i_upload_file_to_filemanager_as($filepath, $filemanagerelement, TableNode $data) { $this->upload_file_to_filemanager($filepath, $filemanagerelement, $data, false); } /** * Uploads a file to the specified filemanager. The paths should be relative to moodle codebase. * * @When /^I upload and overwrite "(?P(?:[^"]|\\")*)" file to "(?P(?:[^"]|\\")*)" filemanager as:$/ * @throws DriverException * @throws ExpectationException Thrown by behat_base::find * @param string $filepath * @param string $filemanagerelement * @param TableNode $data Data to fill in upload form */ public function i_upload_and_overwrite_file_to_filemanager_as($filepath, $filemanagerelement, TableNode $data) { $this->upload_file_to_filemanager($filepath, $filemanagerelement, $data, get_string('overwrite', 'repository')); } /** * Uploads a file to filemanager * * @throws DriverException * @throws ExpectationException Thrown by behat_base::find * @param string $filepath Normally a path relative to $CFG->dirroot, but can be an absolute path too. * @param string $filemanagerelement * @param TableNode $data Data to fill in upload form * @param false|string $overwriteaction false if we don't expect that file with the same name already exists, * or button text in overwrite dialogue ("Overwrite", "Rename to ...", "Cancel") */ protected function upload_file_to_filemanager($filepath, $filemanagerelement, TableNode $data, $overwriteaction = false) { global $CFG; if (!$this->has_tag('_file_upload')) { throw new DriverException('File upload tests must have the @_file_upload tag on either the scenario or feature.'); } $filemanagernode = $this->get_filepicker_node($filemanagerelement); // Opening the select repository window and selecting the upload repository. $this->open_add_file_window($filemanagernode, get_string('pluginname', 'repository_upload')); // Ensure all the form is ready. $noformexception = new ExpectationException('The upload file form is not ready', $this->getSession()); $this->find( 'xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' container ')]" . "[contains(concat(' ', normalize-space(@class), ' '), ' repository_upload ')]" . "/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' file-picker ')]" . "/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-content ')]" . "/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-upload-form ')]" . "/descendant::form", $noformexception ); // After this we have the elements we want to interact with. // Form elements to interact with. $file = $this->find_file('repo_upload_file'); // Attaching specified file to the node. // Replace 'admin/' if it is in start of path with $CFG->admin . if (substr($filepath, 0, 6) === 'admin/') { $filepath = $CFG->dirroot . DIRECTORY_SEPARATOR . $CFG->admin . DIRECTORY_SEPARATOR . substr($filepath, 6); } $filepath = str_replace('/', DIRECTORY_SEPARATOR, $filepath); if (!is_readable($filepath)) { $filepath = $CFG->dirroot . DIRECTORY_SEPARATOR . $filepath; if (!is_readable($filepath)) { throw new ExpectationException('The file to be uploaded does not exist.', $this->getSession()); } } $file->attachFile($filepath); // Fill the form in Upload window. $datahash = $data->getRowsHash(); // The action depends on the field type. foreach ($datahash as $locator => $value) { $field = behat_field_manager::get_form_field_from_label($locator, $this); // Delegates to the field class. $field->set_value($value); } // Submit the file. $submit = $this->find_button(get_string('upload', 'repository')); $submit->press(); // We wait for all the JS to finish as it is performing an action. $this->getSession()->wait(self::get_timeout(), self::PAGE_READY_JS); if ($overwriteaction !== false) { $overwritebutton = $this->find_button($overwriteaction); $overwritebutton->click(); // We wait for all the JS to finish. $this->getSession()->wait(self::get_timeout(), self::PAGE_READY_JS); } } /** * Try to get the filemanager node specified by the element * * @param string $filepickerelement * @return \Behat\Mink\Element\NodeElement * @throws ExpectationException */ protected function get_filepicker_node($filepickerelement) { // More info about the problem (in case there is a problem). $exception = new ExpectationException('"' . $filepickerelement . '" filepicker can not be found', $this->getSession()); // If no file picker label is mentioned take the first file picker from the page. if (empty($filepickerelement)) { $filepickercontainer = $this->find( 'xpath', "//*[@class=\"form-filemanager\"]", $exception ); } else { // Gets the filemanager node specified by the locator which contains the filepicker container // either for filepickers created by mform or by admin config. $filepickerelement = behat_context_helper::escape($filepickerelement); $filepickercontainer = $this->find( 'xpath', "//input[./@id = substring-before(//p[normalize-space(.)=$filepickerelement]/@id, '_label')]" . "//ancestor::*[@data-fieldtype = 'filemanager' or @data-fieldtype = 'filepicker']", $exception ); } return $filepickercontainer; } }