$errors = parent::validation($data, $files);
if (isset($data['feedbackauthorattachment_filemanager']) and isset($this->workshop->overallfeedbackfiletypes)) {
- $whitelist = workshop::normalize_file_extensions($this->workshop->overallfeedbackfiletypes);
+ $filetypesutil = new \core_form\filetypes_util();
+ $whitelist = $filetypesutil->normalize_file_types($this->workshop->overallfeedbackfiletypes);
if ($whitelist) {
$draftfiles = file_get_drafarea_files($data['feedbackauthorattachment_filemanager']);
if ($draftfiles) {
$wrongfiles = array();
foreach ($draftfiles->list as $file) {
- if (!workshop::is_allowed_file_type($file->filename, $whitelist)) {
+ if (!$filetypesutil->is_allowed_file_type($file->filename, $whitelist)) {
$wrongfiles[] = $file->filename;
}
}
if ($wrongfiles) {
$a = array(
- 'whitelist' => workshop::clean_file_extensions($whitelist),
+ 'whitelist' => implode(', ', $whitelist),
'wrongfiles' => implode(', ', $wrongfiles),
);
$errors['feedbackauthorattachment_filemanager'] = get_string('err_wrongfileextension', 'mod_workshop', $a);
+err_unknownfileextension,mod_workshop
yourassessment,mod_workshop
$string['allocationerror'] = 'Allocation error';
$string['allocationconfigured'] = 'Allocation configured';
$string['allowedfiletypesforoverallfeedback'] = 'Feedback attachment allowed file types';
-$string['allowedfiletypesforoverallfeedback_help'] = 'Feedback attachment allowed file types can be restricted by entering a comma-separated list of file extensions, for example \'mp4, mp3, png, jpg\'. If the field is left empty, then all file types are allowed.';
+$string['allowedfiletypesforoverallfeedback_help'] = 'Feedback attachment file types can be restricted by providing a list of allowed file types. If the field is left empty, then all file types are allowed.';
$string['allowedfiletypesforoverallfeedback_link'] = 'admin/tool/filetypes/index';
$string['allowedfiletypesforsubmission'] = 'Submission attachment allowed file types';
-$string['allowedfiletypesforsubmission_help'] = 'Submission attachment allowed file types can be restricted by entering a comma-separated list of file extensions, for example \'mp4, mp3, png, jpg\'. If the field is left empty, then all file types are allowed.';
+$string['allowedfiletypesforsubmission_help'] = 'Submission attachment file types can be restricted by providing a list of allowed file types. If the field is left empty, then all file types are allowed.';
$string['allowedfiletypesforsubmission_link'] = 'admin/tool/filetypes/index';
$string['allsubmissions'] = 'All submissions ({$a})';
$string['alreadygraded'] = 'Already graded';
$string['editsubmission'] = 'Edit submission';
$string['err_multiplesubmissions'] = 'While editing this form, another version of the submission has been saved. Multiple submissions per user are not allowed.';
$string['err_removegrademappings'] = 'Unable to remove the unused grade mappings';
-$string['err_unknownfileextension'] = 'Unknown file extension: {$a}';
$string['err_wrongfileextension'] = 'Some files ({$a->wrongfiles}) cannot be uploaded. Only file types {$a->whitelist} are allowed.';
$string['evaluategradeswait'] = 'Please wait until the assessments are evaluated and the grades are calculated';
$string['evaluation'] = 'Grading evaluation';
// Deprecated since Moodle 3.1.
$string['yourassessment'] = 'Your assessment';
+
+// Deprecated since Moodle 3.4.
+$string['err_unknownfileextension'] = 'Unknown file extension: {$a}';
}
if (isset($workshop->submissionfiletypes)) {
- $workshop->submissionfiletypes = workshop::clean_file_extensions($workshop->submissionfiletypes);
+ $filetypesutil = new \core_form\filetypes_util();
+ $submissionfiletypes = $filetypesutil->normalize_file_types($workshop->submissionfiletypes);
+ $workshop->submissionfiletypes = implode(' ', $submissionfiletypes);
}
if (isset($workshop->overallfeedbackfiletypes)) {
- $workshop->overallfeedbackfiletypes = workshop::clean_file_extensions($workshop->overallfeedbackfiletypes);
+ $filetypesutil = new \core_form\filetypes_util();
+ $overallfeedbackfiletypes = $filetypesutil->normalize_file_types($workshop->overallfeedbackfiletypes);
+ $workshop->overallfeedbackfiletypes = implode(' ', $overallfeedbackfiletypes);
}
// insert the new record so we get the id
}
if (isset($workshop->submissionfiletypes)) {
- $workshop->submissionfiletypes = workshop::clean_file_extensions($workshop->submissionfiletypes);
+ $filetypesutil = new \core_form\filetypes_util();
+ $submissionfiletypes = $filetypesutil->normalize_file_types($workshop->submissionfiletypes);
+ $workshop->submissionfiletypes = implode(' ', $submissionfiletypes);
}
if (isset($workshop->overallfeedbackfiletypes)) {
- $workshop->overallfeedbackfiletypes = workshop::clean_file_extensions($workshop->overallfeedbackfiletypes);
+ $filetypesutil = new \core_form\filetypes_util();
+ $overallfeedbackfiletypes = $filetypesutil->normalize_file_types($workshop->overallfeedbackfiletypes);
+ $workshop->overallfeedbackfiletypes = implode(' ', $overallfeedbackfiletypes);
}
// todo - if the grading strategy is being changed, we may want to replace all aggregated peer grades with nulls
* Empty values are not returned. Values are converted to lowercase.
* Duplicates are removed. Glob evaluation is not supported.
*
+ * @deprecated since Moodle 3.4 MDL-56486 - please use the {@link core_form\filetypes_util}
* @param string|array $extensions list of file extensions
* @return array of strings
*/
public static function normalize_file_extensions($extensions) {
+ debugging('The method workshop::normalize_file_extensions() is deprecated.
+ Please use the methods provided by the \core_form\filetypes_util class.', DEBUG_DEVELOPER);
+
if ($extensions === '') {
return array();
}
/**
* Cleans the user provided list of file extensions.
*
+ * @deprecated since Moodle 3.4 MDL-56486 - please use the {@link core_form\filetypes_util}
* @param string $extensions
* @return string
*/
public static function clean_file_extensions($extensions) {
+ debugging('The method workshop::clean_file_extensions() is deprecated.
+ Please use the methods provided by the \core_form\filetypes_util class.', DEBUG_DEVELOPER);
+
$extensions = self::normalize_file_extensions($extensions);
foreach ($extensions as $i => $extension) {
*
* Empty whitelist is interpretted as "any extension is valid".
*
+ * @deprecated since Moodle 3.4 MDL-56486 - please use the {@link core_form\filetypes_util}
* @param string|array $extensions list of file extensions
* @param string|array $whitelist list of valid extensions
* @return array list of invalid extensions not found in the whitelist
*/
public static function invalid_file_extensions($extensions, $whitelist) {
+ debugging('The method workshop::invalid_file_extensions() is deprecated.
+ Please use the methods provided by the \core_form\filetypes_util class.', DEBUG_DEVELOPER);
+
$extensions = self::normalize_file_extensions($extensions);
$whitelist = self::normalize_file_extensions($whitelist);
* Empty whitelist is interpretted as "any file type is allowed" rather
* than "no file can be uploaded".
*
+ * @deprecated since Moodle 3.4 MDL-56486 - please use the {@link core_form\filetypes_util}
* @param string $filename the file name
* @param string|array $whitelist list of allowed file extensions
* @return false
*/
public static function is_allowed_file_type($filename, $whitelist) {
+ debugging('The method workshop::is_allowed_file_type() is deprecated.
+ Please use the methods provided by the \core_form\filetypes_util class.', DEBUG_DEVELOPER);
+
$whitelist = self::normalize_file_extensions($whitelist);
if (empty($whitelist)) {
'return_types' => FILE_INTERNAL | FILE_CONTROLLED_LINK,
);
- if ($acceptedtypes = self::normalize_file_extensions($this->submissionfiletypes)) {
- $options['accepted_types'] = $acceptedtypes;
- }
+ $filetypesutil = new \core_form\filetypes_util();
+ $options['accepted_types'] = $filetypesutil->normalize_file_types($this->overallfeedbackfiletypes);
return $options;
}
'return_types' => FILE_INTERNAL | FILE_CONTROLLED_LINK,
);
- if ($acceptedtypes = self::normalize_file_extensions($this->overallfeedbackfiletypes)) {
- $options['accepted_types'] = $acceptedtypes;
- }
+ $filetypesutil = new \core_form\filetypes_util();
+ $options['accepted_types'] = $filetypesutil->normalize_file_types($this->overallfeedbackfiletypes);
return $options;
}
$mform->setDefault('nattachments', 1);
$label = get_string('allowedfiletypesforsubmission', 'workshop');
- $mform->addElement('text', 'submissionfiletypes', $label, array('maxlength' => 255, 'size' => 64));
+ $mform->addElement('filetypes', 'submissionfiletypes', $label);
$mform->addHelpButton('submissionfiletypes', 'allowedfiletypesforsubmission', 'workshop');
- $mform->setType('submissionfiletypes', PARAM_TEXT);
- $mform->addRule('submissionfiletypes', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
$mform->disabledIf('submissionfiletypes', 'nattachments', 'eq', 0);
$options = get_max_upload_sizes($CFG->maxbytes, $this->course->maxbytes, 0, $workshopconfig->maxbytes);
$mform->disabledIf('overallfeedbackfiles', 'overallfeedbackmode', 'eq', 0);
$label = get_string('allowedfiletypesforoverallfeedback', 'workshop');
- $mform->addElement('text', 'overallfeedbackfiletypes', $label, array('maxlength' => 255, 'size' => 64));
+ $mform->addElement('filetypes', 'overallfeedbackfiletypes', $label);
$mform->addHelpButton('overallfeedbackfiletypes', 'allowedfiletypesforoverallfeedback', 'workshop');
- $mform->setType('overallfeedbackfiletypes', PARAM_TEXT);
- $mform->addRule('overallfeedbackfiletypes', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
$mform->disabledIf('overallfeedbackfiletypes', 'overallfeedbackfiles', 'eq', 0);
$options = get_max_upload_sizes($CFG->maxbytes, $this->course->maxbytes);
public function validation($data, $files) {
$errors = parent::validation($data, $files);
- // Validate lists of allowed extensions.
- foreach (array('submissionfiletypes', 'overallfeedbackfiletypes') as $fieldname) {
- if (isset($data[$fieldname])) {
- $invalidextensions = workshop::invalid_file_extensions($data[$fieldname], array_keys(core_filetypes::get_types()));
- if ($invalidextensions) {
- $errors[$fieldname] = get_string('err_unknownfileextension', 'mod_workshop',
- workshop::clean_file_extensions($invalidextensions));
- }
- }
- }
-
// check the phases borders are valid
if ($data['submissionstart'] > 0 and $data['submissionend'] > 0 and $data['submissionstart'] >= $data['submissionend']) {
$errors['submissionend'] = get_string('submissionendbeforestart', 'mod_workshop');
}
if (isset($data['attachment_filemanager']) and isset($this->_customdata['workshop']->submissionfiletypes)) {
- $whitelist = workshop::normalize_file_extensions($this->_customdata['workshop']->submissionfiletypes);
+ $filetypesutil = new \core_form\filetypes_util();
+ $whitelist = $filetypesutil->normalize_file_types($this->_customdata['workshop']->submissionfiletypes);
if ($whitelist) {
$draftfiles = file_get_drafarea_files($data['attachment_filemanager']);
if ($draftfiles) {
$wrongfiles = array();
foreach ($draftfiles->list as $file) {
- if (!workshop::is_allowed_file_type($file->filename, $whitelist)) {
+ if (!$filetypesutil->is_allowed_file_type($file->filename, $whitelist)) {
$wrongfiles[] = $file->filename;
}
}
if ($wrongfiles) {
$a = array(
- 'whitelist' => workshop::clean_file_extensions($whitelist),
+ 'whitelist' => implode(', ', $whitelist),
'wrongfiles' => implode(', ', $wrongfiles),
);
$errors['attachment_filemanager'] = get_string('err_wrongfileextension', 'mod_workshop', $a);
--- /dev/null
+@mod @mod_workshop
+Feature: File types of the submission and feedback attachments can be limitted
+ In order to constrain student submission and feedback attachments
+ As a teacher
+ I need to be able to specify the list of allowed file types
+
+ Background:
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | teacher1 | Terry1 | Teacher1 | teacher1@example.com |
+ | student1 | Sam1 | Student1 | student1@example.com |
+ | student2 | Sam2 | Student2 | student2@example.com |
+ And the following "courses" exist:
+ | fullname | shortname |
+ | Course1 | c1 |
+ And the following "course enrolments" exist:
+ | user | course | role |
+ | teacher1 | c1 | editingteacher |
+ | student1 | c1 | student |
+ | student2 | c1 | student |
+ And the following "activities" exist:
+ | activity | name | intro | course | idnumber |
+ | workshop | TestWorkshop | Test workshop description | c1 | workshop1 |
+
+ @_file_upload @javascript
+ Scenario: Student submission attachments obey the list of allowed file types
+ # Define workshop to accept only images as submission attachments.
+ Given I log in as "teacher1"
+ And I am on "Course1" course homepage
+ And I follow "TestWorkshop"
+ And I navigate to "Edit settings" in current page administration
+ And I expand all fieldsets
+ And I set the field "Submission attachment allowed file types" to "image"
+ And I press "Save and display"
+ And I change phase in workshop "TestWorkshop" to "Submission phase"
+ And I log out
+ # As a student, attempt to attach a non-image file.
+ And I log in as "student1"
+ And I am on "Course1" course homepage
+ And I follow "TestWorkshop"
+ And I press "Start preparing your submission"
+ And I set the following fields to these values:
+ | Title | Submission1 |
+ | Submission content | See the attached file |
+ And I upload "mod/workshop/tests/fixtures/testable.php" file to "Attachment" filemanager
+ When I press "Save changes"
+ Then I should see "Some files (testable.php) cannot be uploaded. Only file types image are allowed."
+ # Remove the invalid file and attach an image instead.
+ And I delete "testable.php" from "Attachment" filemanager
+ And I upload "mod/workshop/tests/fixtures/moodlelogo.png" file to "Attachment" filemanager
+ And I press "Save changes"
+ And "//div[@class='submission-full' and contains(.,'Submission1') and contains(.,'submitted on')]" "xpath_element" should exist
+
+ @_file_upload @javascript
+ Scenario: Overall feedback attachments obey the list of allowed file types
+ # Define workshop to accept only .php files as overall feedback attachments.
+ Given I log in as "teacher1"
+ And I am on "Course1" course homepage
+ And I edit assessment form in workshop "TestWorkshop" as:"
+ | id_description__idx_0_editor | Aspect1 |
+ | id_description__idx_1_editor | Aspect2 |
+ | id_description__idx_2_editor | |
+ And I follow "TestWorkshop"
+ And I navigate to "Edit settings" in current page administration
+ And I expand all fieldsets
+ And I set the field "Maximum number of overall feedback attachments" to "2"
+ And I set the field "Feedback attachment allowed file types" to "PHP"
+ And I press "Save and display"
+ And I change phase in workshop "TestWorkshop" to "Submission phase"
+ And I log out
+ # As a student, attempt to attach an invalid file.
+ And I log in as "student1"
+ And I am on "Course1" course homepage
+ And I follow "TestWorkshop"
+ And I add a submission in workshop "TestWorkshop" as:"
+ | Title | Submission1 |
+ | Submission content | Some content |
+ And I log out
+ # As a teacher, allocate that submission to be assessed by another student.
+ And I log in as "teacher1"
+ And I am on "Course1" course homepage
+ And I follow "TestWorkshop"
+ And I allocate submissions in workshop "TestWorkshop" as:"
+ | Participant | Reviewer |
+ | Sam1 Student1 | Sam2 Student2 |
+ And I change phase in workshop "TestWorkshop" to "Assessment phase"
+ And I log out
+ # As the other student, assess the assigned submission.
+ And I log in as "student2"
+ And I am on "Course1" course homepage
+ And I follow "TestWorkshop"
+ And I follow "Submission1"
+ And I press "Assess"
+ And I set the following fields to these values:
+ | grade__idx_0 | 5 / 10 |
+ | peercomment__idx_0 | You can do better |
+ | grade__idx_1 | 10 / 10 |
+ | peercomment__idx_1 | Amazing |
+ | Feedback for the author | Good work |
+ # We can't directly upload the invalid file here as the upload repository would throw an exception.
+ # So instead we try to trick the filemanager and bypass its checks, to be finally stopped by the
+ # form field validation.
+ And I upload "mod/workshop/tests/fixtures/testable.php" file to "Attachment" filemanager
+ And I follow "testable.php"
+ And I set the field "Name" to "renamed.png"
+ And I press "Update"
+ When I press "Save and close"
+ Then I should see "Some files (renamed.png) cannot be uploaded. Only file types .php are allowed."
+ # Finally make sure that allowed file gets uploaded.
+ And I delete "renamed.png" from "Attachment" filemanager
+ And I upload "mod/workshop/tests/fixtures/testable.php" file to "Attachment" filemanager
+ And I press "Save and close"
+ And I should see "Assigned submissions to assess"
+ And I should see "Re-assess"
public function test_normalize_file_extensions() {
$this->resetAfterTest(true);
- $this->assertSame(['.odt'], workshop::normalize_file_extensions('odt'));
- $this->assertSame(['.odt'], workshop::normalize_file_extensions('.odt'));
- $this->assertSame(['.odt'], workshop::normalize_file_extensions('.ODT'));
- $this->assertSame(['.doc', '.jpg', '.mp3'], workshop::normalize_file_extensions('doc, jpg, mp3'));
- $this->assertSame(['.doc', '.jpg', '.mp3'], workshop::normalize_file_extensions(['.doc', '.jpg', '.mp3']));
- $this->assertSame(['.doc', '.jpg', '.mp3'], workshop::normalize_file_extensions('doc, *.jpg, mp3'));
- $this->assertSame(['.doc', '.jpg', '.mp3'], workshop::normalize_file_extensions(['doc ', ' JPG ', '.mp3']));
- $this->assertSame(['.rtf', '.pdf', '.docx'], workshop::normalize_file_extensions("RTF,.pdf\n...DocX,,,;\rPDF\trtf ...Rtf"));
- $this->assertSame(['.tgz', '.tar.gz'], workshop::normalize_file_extensions('tgz,TAR.GZ tar.gz .tar.gz tgz TGZ'));
- $this->assertSame(['.notebook'], workshop::normalize_file_extensions('"Notebook":notebook;NOTEBOOK;,\'NoTeBook\''));
- $this->assertSame([], workshop::normalize_file_extensions(''));
- $this->assertSame([], workshop::normalize_file_extensions([]));
- $this->assertSame(['.0'], workshop::normalize_file_extensions(0));
- $this->assertSame(['.0'], workshop::normalize_file_extensions('0'));
- $this->assertSame(['.odt'], workshop::normalize_file_extensions('*.odt'));
- $this->assertSame([], workshop::normalize_file_extensions('.'));
- $this->assertSame(['.foo'], workshop::normalize_file_extensions('. foo'));
- $this->assertSame([], workshop::normalize_file_extensions('*'));
- $this->assertSame([], workshop::normalize_file_extensions('*~'));
- $this->assertSame(['.pdf', '.ps'], workshop::normalize_file_extensions('* pdf *.ps foo* *bar .r??'));
+ workshop::normalize_file_extensions('');
+ $this->assertDebuggingCalled();
}
/**
public function test_clean_file_extensions() {
$this->resetAfterTest(true);
- $this->assertSame('', workshop::clean_file_extensions(''));
- $this->assertSame('', workshop::clean_file_extensions(null));
- $this->assertSame('', workshop::clean_file_extensions(' '));
- $this->assertSame('0', workshop::clean_file_extensions(0));
- $this->assertSame('0', workshop::clean_file_extensions('0'));
- $this->assertSame('doc, rtf, pdf', workshop::clean_file_extensions('*.Doc, RTF, PDF, .rtf'.PHP_EOL.'PDF '));
- $this->assertSame('doc, rtf, pdf', 'doc, rtf, pdf');
+ workshop::clean_file_extensions('');
+ $this->assertDebuggingCalledCount(2);
}
/**
public function test_invalid_file_extensions() {
$this->resetAfterTest(true);
- $this->assertSame([], workshop::invalid_file_extensions('', ''));
- $this->assertSame([], workshop::invalid_file_extensions('', '.doc'));
- $this->assertSame([], workshop::invalid_file_extensions('odt', ''));
- $this->assertSame([], workshop::invalid_file_extensions('odt', '*'));
- $this->assertSame([], workshop::invalid_file_extensions('odt', 'odt'));
- $this->assertSame([], workshop::invalid_file_extensions('doc, odt, pdf', ['pdf', 'doc', 'odt']));
- $this->assertSame([], workshop::invalid_file_extensions(['doc', 'odt', 'PDF'], ['.doc', '.pdf', '.odt']));
- $this->assertSame([], workshop::invalid_file_extensions('*~ .docx, Odt PDF :doc .pdf', '*.docx *.odt *.pdf *.doc'));
- $this->assertSame(['.00001-wtf-is-this'], workshop::invalid_file_extensions('docx tgz .00001-wtf-is-this', 'tgz docx'));
- $this->assertSame(['.foobar', '.wtfisthis'], workshop::invalid_file_extensions(['.pdf', '.foobar', 'wtfisthis'], 'pdf'));
- $this->assertSame([], workshop::invalid_file_extensions('', ''));
- $this->assertSame(['.odt'], workshop::invalid_file_extensions(['.PDF', 'PDF', '.ODT'], 'jpg pdf png gif'));
- $this->assertSame(['.odt'], workshop::invalid_file_extensions(['.PDF', 'PDF', '.ODT'], '.jpg,.pdf, .png .gif'));
- $this->assertSame(['.exe', '.bat'], workshop::invalid_file_extensions(['.exe', '.odt', '.bat', ''], 'odt'));
+ workshop::invalid_file_extensions('', '');
+ $this->assertDebuggingCalledCount(3);
}
/**
public function test_is_allowed_file_type() {
$this->resetAfterTest(true);
- $this->assertTrue(workshop::is_allowed_file_type('README.txt', ''));
- $this->assertTrue(workshop::is_allowed_file_type('README.txt', ['']));
- $this->assertFalse(workshop::is_allowed_file_type('README.txt', '0'));
-
- $this->assertFalse(workshop::is_allowed_file_type('README.txt', 'xt'));
- $this->assertFalse(workshop::is_allowed_file_type('README.txt', 'old.txt'));
-
- $this->assertTrue(workshop::is_allowed_file_type('README.txt', 'txt'));
- $this->assertTrue(workshop::is_allowed_file_type('README.txt', '.TXT'));
- $this->assertTrue(workshop::is_allowed_file_type('README.TXT', 'txt'));
- $this->assertTrue(workshop::is_allowed_file_type('README.txt', '.txt .md'));
- $this->assertTrue(workshop::is_allowed_file_type('README.txt', 'HTML TXT DOC RTF'));
- $this->assertTrue(workshop::is_allowed_file_type('README.txt', ['HTML', '...TXT', 'DOC', 'RTF']));
-
- $this->assertTrue(workshop::is_allowed_file_type('C:\Moodle\course-data.tar.gz', 'gzip zip 7z tar.gz'));
- $this->assertFalse(workshop::is_allowed_file_type('C:\Moodle\course-data.tar.gz', 'gzip zip 7z tar'));
- $this->assertTrue(workshop::is_allowed_file_type('~/course-data.tar.gz', 'gzip zip 7z gz'));
- $this->assertFalse(workshop::is_allowed_file_type('~/course-data.tar.gz', 'gzip zip 7z'));
-
- $this->assertFalse(workshop::is_allowed_file_type('Alice on the beach.jpg.exe', 'png gif jpg bmp'));
- $this->assertFalse(workshop::is_allowed_file_type('xfiles.exe.jpg', 'exe com bat sh'));
- $this->assertFalse(workshop::is_allowed_file_type('solution.odt~', 'odt, xls'));
- $this->assertTrue(workshop::is_allowed_file_type('solution.odt~', 'odt, odt~'));
+ workshop::is_allowed_file_type('', '');
+ $this->assertDebuggingCalledCount(2);
}
/**