Merge branch 'MDL-39913-master-new-validation' of https://github.com/xow/moodle

This commit is contained in:
Andrew Nicols 2017-04-13 08:44:15 +08:00
commit 28b966a5f9
7 changed files with 309 additions and 13 deletions

View File

@ -40,17 +40,48 @@ $string['application/msword'] = 'Word document';
$string['application/pdf'] = 'PDF document';
$string['application/vnd.moodle.backup'] = 'Moodle backup';
$string['application/vnd.ms-excel'] = 'Excel spreadsheet';
$string['application/vnd.ms-excel.sheet.macroEnabled.12'] = 'Excel 2007 macro-enabled workbook';
$string['application/vnd.ms-powerpoint'] = 'Powerpoint presentation';
$string['application/vnd.openxmlformats-officedocument.presentationml.presentation'] = 'Powerpoint presentation';
$string['application/vnd.openxmlformats-officedocument.presentationml.slideshow'] = 'Powerpoint slideshow';
$string['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] = 'Excel spreadsheet';
$string['application/vnd.openxmlformats-officedocument.spreadsheetml.template'] = 'Excel template';
$string['application/vnd.openxmlformats-officedocument.wordprocessingml.document'] = 'Word document';
$string['application/vnd.oasis.opendocument.spreadsheet'] = 'OpenDocument Spreadsheet';
$string['application/vnd.oasis.opendocument.spreadsheet-template'] = 'OpenDocument Spreadsheet template';
$string['application/vnd.oasis.opendocument.text'] = 'OpenDocument Text document';
$string['application/vnd.oasis.opendocument.text-template'] = 'OpenDocument Text template';
$string['application/vnd.oasis.opendocument.text-web'] = 'OpenDocument Web page template';
$string['application/vnd.openxmlformats-officedocument.presentationml.presentation'] = 'Powerpoint 2007 presentation';
$string['application/vnd.openxmlformats-officedocument.presentationml.slideshow'] = 'Powerpoint 2007 slideshow';
$string['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] = 'Excel 2007 spreadsheet';
$string['application/vnd.openxmlformats-officedocument.spreadsheetml.template'] = 'Excel 2007 template';
$string['application/vnd.openxmlformats-officedocument.wordprocessingml.document'] = 'Word 2007 document';
$string['application/x-iwork-keynote-sffkey'] = 'iWork Keynote presentation';
$string['application/x-iwork-numbers-sffnumbers'] = 'iWork Numbers spreadsheet';
$string['application/x-iwork-pages-sffpages'] = 'iWork Pages document';
$string['application/x-javascript'] = 'JavaScript source';
$string['application/x-mspublisher'] = 'Publisher document';
$string['application/x-shockwave-flash'] = 'Flash animation';
$string['application/xhtml_xml'] = 'XHTML document';
$string['archive'] = 'Archive ({$a->EXT})';
$string['audio'] = 'Audio file ({$a->EXT})';
$string['default'] = '{$a->mimetype}';
$string['document/unknown'] = 'File';
$string['group:archive'] = 'Archive files';
$string['group:audio'] = 'Audio files';
$string['group:document'] = 'Document files';
$string['group:html_audio'] = 'Audio files natively supported by browsers';
$string['group:html_track'] = 'HTML track files';
$string['group:html_video'] = 'Video files natively supported by browsers';
$string['group:image'] = 'Image files';
$string['group:presentation'] = 'Presentation files';
$string['group:sourcecode'] = 'Source code';
$string['group:spreadsheet'] = 'Spreadsheet files';
$string['group:video'] = 'Video files';
$string['group:web_audio'] = 'Audio files used on the web';
$string['group:web_file'] = 'Web files';
$string['group:web_image'] = 'Image files used on the web';
$string['group:web_video'] = 'Video files used on the web';
$string['image'] = 'Image ({$a->MIMETYPE2})';
$string['image/vnd.microsoft.icon'] = 'Windows icon';
$string['text/css'] = 'Cascading Style-Sheet';
$string['text/csv'] = 'Comma-separated values';
$string['text/html'] = 'HTML document';
$string['text/plain'] = 'Text file';
$string['text/rtf'] = 'RTF document';

View File

@ -90,7 +90,7 @@ abstract class core_filetypes {
'dxr' => array('type' => 'application/x-director', 'icon' => 'flash'),
'eps' => array('type' => 'application/postscript', 'icon' => 'eps'),
'epub' => array('type' => 'application/epub+zip', 'icon' => 'epub', 'groups' => array('document')),
'fdf' => array('type' => 'application/pdf', 'icon' => 'pdf'),
'fdf' => array('type' => 'application/vnd.fdf', 'icon' => 'pdf'),
'flac' => array('type' => 'audio/flac', 'icon' => 'audio', 'groups' => array('audio', 'html_audio', 'web_audio'),
'string' => 'audio'),
'flv' => array('type' => 'video/x-flv', 'icon' => 'flash',
@ -197,7 +197,7 @@ abstract class core_filetypes {
'string' => 'video'),
'pct' => array('type' => 'image/pict', 'icon' => 'image', 'groups' => array('image'), 'string' => 'image'),
'pdf' => array('type' => 'application/pdf', 'icon' => 'pdf'),
'pdf' => array('type' => 'application/pdf', 'icon' => 'pdf', 'groups' => array('document')),
'php' => array('type' => 'text/plain', 'icon' => 'sourcecode'),
'pic' => array('type' => 'image/pict', 'icon' => 'image', 'groups' => array('image'), 'string' => 'image'),
'pict' => array('type' => 'image/pict', 'icon' => 'image', 'groups' => array('image'), 'string' => 'image'),
@ -283,12 +283,13 @@ abstract class core_filetypes {
'wma' => array('type' => 'audio/x-ms-wma', 'icon' => 'audio', 'groups' => array('audio'), 'string' => 'audio'),
'xbk' => array('type' => 'application/x-smarttech-notebook', 'icon' => 'archive'),
'xdp' => array('type' => 'application/pdf', 'icon' => 'pdf'),
'xfd' => array('type' => 'application/pdf', 'icon' => 'pdf'),
'xfdf' => array('type' => 'application/pdf', 'icon' => 'pdf'),
'xdp' => array('type' => 'application/vnd.adobe.xdp+xml', 'icon' => 'pdf'),
'xfd' => array('type' => 'application/vnd.xfdl', 'icon' => 'pdf'),
'xfdf' => array('type' => 'application/vnd.adobe.xfdf', 'icon' => 'pdf'),
'xls' => array('type' => 'application/vnd.ms-excel', 'icon' => 'spreadsheet', 'groups' => array('spreadsheet')),
'xlsx' => array('type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'icon' => 'spreadsheet'),
'xlsx' => array('type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'icon' => 'spreadsheet',
'groups' => array('spreadsheet')),
'xlsm' => array('type' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
'icon' => 'spreadsheet', 'groups' => array('spreadsheet')),
'xltx' => array('type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',

View File

@ -23,6 +23,8 @@
*/
$string['acceptedfiletypes'] = 'Accepted file types';
$string['acceptedfiletypes_help'] = 'Accepted file types can be restricted by entering a semicolon-separated list of mimetypes, for example \'video/mp4; audio/mp3; image/png; image/jpeg\'. You may also limit to extensions by including the dot, for example \'.png; .jpg\' If the field is left empty, then all file types are allowed.';
$string['configmaxbytes'] = 'Maximum file size';
$string['countfiles'] = '{$a} files';
$string['default'] = 'Enabled by default';
@ -31,6 +33,8 @@ $string['enabled'] = 'File submissions';
$string['enabled_help'] = 'If enabled, students are able to upload one or more files as their submission.';
$string['eventassessableuploaded'] = 'A file has been uploaded.';
$string['file'] = 'File submissions';
$string['filesofthesetypes'] = 'Files of these types may be added to the submission:';
$string['filetypewithexts'] = '{$a->name} — {$a->extlist}';
$string['maxbytes'] = 'Maximum file size';
$string['maxfiles'] = 'Maximum files per submission';
$string['maxfiles_help'] = 'If file submissions are enabled, each assignment can be set to accept up to this number of files for their submission.';
@ -38,6 +42,7 @@ $string['maxfilessubmission'] = 'Maximum number of uploaded files';
$string['maxfilessubmission_help'] = 'If file submissions are enabled, each student will be able to upload up to this number of files for their submission.';
$string['maximumsubmissionsize'] = 'Maximum submission size';
$string['maximumsubmissionsize_help'] = 'Files uploaded by students may be up to this size.';
$string['nonexistentfiletypes'] = 'The following file types were not recognised: {$a}';
$string['numfilesforlog'] = 'The number of file(s) : {$a} file(s).';
$string['pluginname'] = 'File submissions';
$string['siteuploadlimit'] = 'Site upload limit';

View File

@ -71,6 +71,7 @@ class assign_submission_file extends assign_submission_plugin {
$defaultmaxfilesubmissions = $this->get_config('maxfilesubmissions');
$defaultmaxsubmissionsizebytes = $this->get_config('maxsubmissionsizebytes');
$defaultfiletypes = (string)$this->get_config('filetypeslist');
$settings = array();
$options = array();
@ -105,6 +106,25 @@ class assign_submission_file extends assign_submission_plugin {
$mform->disabledIf('assignsubmission_file_maxsizebytes',
'assignsubmission_file_enabled',
'notchecked');
$name = get_string('acceptedfiletypes', 'assignsubmission_file');
$mform->addElement('text', 'assignsubmission_file_filetypes', $name);
$mform->addHelpButton('assignsubmission_file_filetypes', 'acceptedfiletypes', 'assignsubmission_file');
$mform->setType('assignsubmission_file_filetypes', PARAM_RAW);
$mform->setDefault('assignsubmission_file_filetypes', $defaultfiletypes);
$mform->disabledIf('assignsubmission_file_filetypes', 'assignsubmission_file_enabled', 'notchecked');
$mform->addFormRule(function ($values, $files) {
if (empty($values['assignsubmission_file_filetypes'])) {
return true;
}
$nonexistent = $this->get_nonexistent_file_types($values['assignsubmission_file_filetypes']);
if (empty($nonexistent)) {
return true;
} else {
$a = join(' ', $nonexistent);
return ["assignsubmission_file_filetypes" => get_string('nonexistentfiletypes', 'assignsubmission_file', $a)];
}
});
}
/**
@ -116,6 +136,13 @@ class assign_submission_file extends assign_submission_plugin {
public function save_settings(stdClass $data) {
$this->set_config('maxfilesubmissions', $data->assignsubmission_file_maxfiles);
$this->set_config('maxsubmissionsizebytes', $data->assignsubmission_file_maxsizebytes);
if (!empty($data->assignsubmission_file_filetypes)) {
$this->set_config('filetypeslist', $data->assignsubmission_file_filetypes);
} else {
$this->set_config('filetypeslist', '');
}
return true;
}
@ -128,7 +155,7 @@ class assign_submission_file extends assign_submission_plugin {
$fileoptions = array('subdirs' => 1,
'maxbytes' => $this->get_config('maxsubmissionsizebytes'),
'maxfiles' => $this->get_config('maxfilesubmissions'),
'accepted_types' => '*',
'accepted_types' => $this->get_accepted_types(),
'return_types' => (FILE_INTERNAL | FILE_CONTROLLED_LINK));
if ($fileoptions['maxbytes'] == 0) {
// Use module default.
@ -163,6 +190,34 @@ class assign_submission_file extends assign_submission_plugin {
$submissionid);
$mform->addElement('filemanager', 'files_filemanager', $this->get_name(), null, $fileoptions);
if (!empty($this->get_config('filetypeslist'))) {
$text = html_writer::tag('p', get_string('filesofthesetypes', 'assignsubmission_file'));
$text .= html_writer::start_tag('ul');
$typesets = $this->get_configured_typesets();
foreach ($typesets as $type) {
$a = new stdClass();
$extensions = file_get_typegroup('extension', $type);
$typetext = html_writer::tag('li', $type);
// Only bother checking if it's a mimetype or group if it has extensions in the group.
if (!empty($extensions)) {
if (strpos($type, '/') !== false) {
$a->name = get_mimetype_description($type);
$a->extlist = implode(' ', $extensions);
$typetext = html_writer::tag('li', get_string('filetypewithexts', 'assignsubmission_file', $a));
} else if (get_string_manager()->string_exists("group:$type", 'mimetypes')) {
$a->name = get_string("group:$type", 'mimetypes');
$a->extlist = implode(' ', $extensions);
$typetext = html_writer::tag('li', get_string('filetypewithexts', 'assignsubmission_file', $a));
}
}
$text .= $typetext;
}
$text .= html_writer::end_tag('ul');
$mform->addElement('static', '', '', $text);
}
return true;
}
@ -570,4 +625,70 @@ class assign_submission_file extends assign_submission_plugin {
}
return (array) $configs;
}
/**
* Get the type sets configured for this assignment.
*
* @return array('groupname', 'mime/type', ...)
*/
private function get_configured_typesets() {
$typeslist = (string)$this->get_config('filetypeslist');
$sets = $this->get_typesets($typeslist);
return $sets;
}
/**
* Get the type sets passed.
*
* @param string $types The space , ; separated list of types
* @return array('groupname', 'mime/type', ...)
*/
private function get_typesets($types) {
$sets = array();
if (!empty($types)) {
$sets = preg_split('/[\s,;:"\']+/', $types, null, PREG_SPLIT_NO_EMPTY);
}
return $sets;
}
/**
* Return the accepted types list for the file manager component.
*
* @return array|string
*/
private function get_accepted_types() {
$acceptedtypes = $this->get_configured_typesets();
if (!empty($acceptedtypes)) {
return $acceptedtypes;
}
return '*';
}
/**
* List the nonexistent file types that need to be removed.
*
* @param string $types space , or ; separated types
* @return array A list of the nonexistent file types.
*/
private function get_nonexistent_file_types($types) {
$nonexistent = [];
foreach ($this->get_typesets($types) as $type) {
$coretypes = core_filetypes::get_types();
// We can allow any extension, but validate groups & mimetypes.
if (strpos($type, '.') === false) {
// If there's no dot, check if it's a group.
$extensions = file_get_typegroup('extension', [$type]);
if (empty($extensions)) {
// If there's no extensions under that group, it doesn't exist.
$nonexistent[$type] = true;
}
}
}
return array_keys($nonexistent);
}
}

View File

@ -0,0 +1,74 @@
@mod @mod_assign @assignsubmission_file
Feature: In an assignment, limit submittable file types
In order to constrain student submissions for marking
As a teacher
I need to limit the submittable file types
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| student1 | Student | 1 | student1@example.com |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And the following config values are set as admin:
| filetypes | image/png;spreadsheet | assignsubmission_file |
@javascript
Scenario: File types validation for an assignment
Given the following "activities" exist:
| activity | course | idnumber | name | intro | duedate | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | assignsubmission_file_maxfiles | assignsubmission_file_maxsizebytes |
| assign | C1 | assign1 | Test assignment name | Test assignment description | 1388534400 | 0 | 1 | 1 | 0 |
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I follow "Test assignment name"
And I navigate to "Edit settings" in current page administration
When I set the field "Accepted file types" to "image/png;doesntexist;.anything;unreal/mimetype;nodot"
And I press "Save and display"
And I should see "The following file types were not recognised: doesntexist unreal/mimetype nodot"
And I set the field "Accepted file types" to "image/png;spreadsheet"
And I press "Save and display"
And I navigate to "Edit settings" in current page administration
Then the field "Accepted file types" matches value "image/png;spreadsheet"
@javascript @_file_upload
Scenario: Uploading permitted file types for an assignment
Given the following "activities" exist:
| activity | course | idnumber | name | intro | duedate | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | assignsubmission_file_maxfiles | assignsubmission_file_maxsizebytes | assignsubmission_file_filetypes |
| assign | C1 | assign1 | Test assignment name | Test assignment description | 1388534400 | 0 | 1 | 3 | 0 | image/png;spreadsheet;.xml;.txt |
And I log in as "student1"
And I am on "Course 1" course homepage
And I follow "Test assignment name"
When I press "Add submission"
And I should see "Files of these types may be added to the submission"
And I should see "Image (PNG) .png"
And I should see "Spreadsheet files .csv .gsheet .ods .ots .xls .xlsx .xlsm"
And I should see ".txt"
And I upload "lib/tests/fixtures/gd-logo.png" file to "File submissions" filemanager
And I upload "lib/tests/fixtures/tabfile.csv" file to "File submissions" filemanager
And I upload "lib/tests/fixtures/empty.txt" file to "File submissions" filemanager
And I press "Save changes"
Then "gd-logo.png" "link" should exist
And "tabfile.csv" "link" should exist
And "empty.txt" "link" should exist
@javascript @_file_upload
Scenario: No filetypes allows all
Given the following "activities" exist:
| activity | course | idnumber | name | intro | duedate | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled | assignsubmission_file_maxfiles | assignsubmission_file_maxsizebytes | assignsubmission_file_filetypes |
| assign | C1 | assign1 | Test assignment name | Test assignment description | 1388534400 | 0 | 1 | 2 | 0 | |
And I log in as "student1"
And I am on "Course 1" course homepage
And I follow "Test assignment name"
When I press "Add submission"
And I should not see "Files of these types may be added to the submission"
And I upload "lib/tests/fixtures/gd-logo.png" file to "File submissions" filemanager
And I upload "lib/tests/fixtures/tabfile.csv" file to "File submissions" filemanager
And I press "Save changes"
Then "gd-logo.png" "link" should exist
And "tabfile.csv" "link" should exist

View File

@ -137,5 +137,69 @@ class assignsubmission_file_locallib_testcase extends advanced_testcase {
];
}
/**
* Data provider for testing test_get_nonexistent_file_types.
*
* @return array
*/
public function get_nonexistent_file_types_provider() {
return [
'Nonexistent extensions are allowed' => [
'filetypes' => '.rat',
'expected' => []
],
'Multiple nonexistent extensions are allowed' => [
'filetypes' => '.ricefield .rat',
'expected' => []
],
'Existent extension is allowed' => [
'filetypes' => '.xml',
'expected' => []
],
'Existent group is allowed' => [
'filetypes' => 'web_file',
'expected' => []
],
'Nonexistent group is not allowed' => [
'filetypes' => '©ç√√ß∂å√©åß©√',
'expected' => ['©ç√√ß∂å√©åß©√']
],
'Existent mimetype is allowed' => [
'filetypes' => 'application/xml',
'expected' => []
],
'Nonexistent mimetype is not allowed' => [
'filetypes' => 'ricefield/rat',
'expected' => ['ricefield/rat']
],
'Multiple nonexistent mimetypes are not allowed' => [
'filetypes' => 'ricefield/rat cam/ball',
'expected' => ['ricefield/rat', 'cam/ball']
],
'Missing dot in extension is not allowed' => [
'filetypes' => 'png',
'expected' => ['png']
],
'Some existent some not' => [
'filetypes' => '.txt application/xml web_file ©ç√√ß∂å√©åß©√ .png ricefield/rat document png',
'expected' => ['©ç√√ß∂å√©åß©√', 'ricefield/rat', 'png']
]
];
}
/**
* Test get_nonexistent_file_types().
* @dataProvider get_nonexistent_file_types_provider
* @param string $filetypes The filetypes to check
* @param array $expected The expected result. The list of non existent file types.
*/
public function test_get_nonexistent_file_types($filetypes, $expected) {
$this->resetAfterTest();
$method = new ReflectionMethod(assign_submission_file::class, 'get_nonexistent_file_types');
$method->setAccessible(true);
$plugin = $this->assign->get_submission_plugin_by_type('file');
$nonexistentfiletypes = $method->invokeArgs($plugin, [$filetypes]);
$this->assertSame($expected, $nonexistentfiletypes);
}
}

View File

@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2016120500;
$plugin->version = 2017032000;
$plugin->requires = 2016112900;
$plugin->component = 'assignsubmission_file';