diff --git a/amd/build/submissionform.min.js b/amd/build/submissionform.min.js new file mode 100644 index 0000000000000000000000000000000000000000..6dbfeb52d52ab02230b3d5689ae72aa51a7e71b9 --- /dev/null +++ b/amd/build/submissionform.min.js @@ -0,0 +1 @@ +define(["jquery"],function(a){function b(b){"archive"==b?(a("#id_headersubmitarchive").show().removeClass("collapsed"),a("#id_headersubmitfiles").hide()):(a("#id_headersubmitarchive").hide(),a("#id_headersubmitfiles").show().removeClass("collapsed"))}return{setup:function(){var c=a('select[name="submitmethod"]');c.change(function(){b(c.val())}),b(c.val())}}}); \ No newline at end of file diff --git a/amd/src/submissionform.js b/amd/src/submissionform.js new file mode 100644 index 0000000000000000000000000000000000000000..87314689eb8eeff494983846af0d4d1d00cd1b15 --- /dev/null +++ b/amd/src/submissionform.js @@ -0,0 +1,21 @@ +define(['jquery'], function($) { + function updateHeaders(submitType) { + if (submitType == 'archive') { + $('#id_headersubmitarchive').show().removeClass('collapsed'); + $('#id_headersubmitfiles').hide(); + } else { + $('#id_headersubmitarchive').hide(); + $('#id_headersubmitfiles').show().removeClass('collapsed'); + } + } + + return { + setup: function() { + var $select = $('select[name="submitmethod"]'); + $select.change(function() { + updateHeaders($select.val()); + }); + updateHeaders($select.val()); + } + }; +}); \ No newline at end of file diff --git a/forms/submission.php b/forms/submission.php index 984f8b5027b7244085da6848267c2ea43c4dcba3..019133ba847f95f1c70a428dac445ea9fcc47c2e 100644 --- a/forms/submission.php +++ b/forms/submission.php @@ -56,7 +56,7 @@ if ($userid == $USER->id) { // Make own submission. $instance = $vpl->get_instance(); $vpl->print_header( get_string( 'submission', VPL ) ); $vpl->print_view_tabs( basename( __FILE__ ) ); -$mform = new mod_vpl_submission_form( 'submission.php', $vpl ); +$mform = new mod_vpl_submission_form( 'submission.php', $vpl, $userid ); if ($mform->is_cancelled()) { vpl_inmediate_redirect( vpl_mod_href( 'view.php', 'id', $id ) ); die(); @@ -72,23 +72,79 @@ if ($fromform = $mform->get_data()) { $rfn = $vpl->get_fgm('required'); $reqfiles = $rfn->getFileList(); $files = array (); - for ($i = 0; $i < $instance->maxfiles; $i ++) { - $attribute = 'file' . $i; - $name = $mform->get_new_filename( $attribute ); - $data = $mform->get_file_content( $attribute ); - if ($data !== false && $name !== false) { + $prevsub = $vpl->last_user_submission( $userid ); + $firstsub = ($prevsub === false); + $prevsubfiles = (new mod_vpl_submission( $vpl, $prevsub ))->get_submitted_fgm()->getAllFiles(); + if ($fromform->submitmethod == 'archive') { + if (!$firstsub && $fromform->archiveaction == 'replace') { + // Use files of previous submission. + foreach ($prevsubfiles as $subfilename => $subfilecontent) { + $files[$subfilename] = $subfilecontent; + } + } + // Open archive. + $zipname = $mform->save_temp_file( 'archive' ); + $zip = new ZipArchive(); + $zip->open($zipname); + $subreqfiles = array(); + $subotherfiles = array(); + // Read archive and split between required / additional files. + for ($i = 0; $i < $zip->numFiles; $i++) { + $filename = $zip->statIndex($i)['name']; + $filecontent = file_get_contents('zip://' . $zipname . '#' . $filename); // Autodetect text file encode if not binary. - if (! vpl_is_binary( $name )) { - $encode = mb_detect_encoding( $data, 'UNICODE, UTF-16, UTF-8, ISO-8859-1', true ); - if ($encode > '') { // If code detected. - $data = iconv( $encode, 'UTF-8', $data ); + if (! vpl_is_binary( $filename )) { + $encoding = mb_detect_encoding( $filecontent, 'UNICODE, UTF-16, UTF-8, ISO-8859-1', true ); + if ($encoding > '') { // If code detected. + $filecontent = iconv( $encoding, 'UTF-8', $filecontent ); + } + } else { + if (in_array($filename . '.b64', $reqfiles)) { + $filename = $filename . '.b64'; + $filecontent = base64_encode($filecontent); } - $files [$name] = $data; + } + if (in_array($filename, $reqfiles)) { + $subreqfiles[$filename] = $filecontent; + } else { + $subotherfiles[$filename] = $filecontent; + } + } + foreach ($reqfiles as $reqfile) { + if (isset($subreqfiles[$reqfile])) { + $files[$reqfile] = $subreqfiles[$reqfile]; + } + } + foreach ($subotherfiles as $filename => $filecontent) { + $files[$filename] = $filecontent; + } + // Close archive. + $zip->close(); + unlink($zipname); + } else { + for ($i = 0; $i < $instance->maxfiles; $i ++) { + $field = 'file' . $i; + if (!$firstsub && isset($fromform->{$field . 'action'}) && $fromform->{$field . 'action'} == 'keep') { + $filename = $fromform->{$field . 'name'}; + $files[$filename] = $prevsubfiles[$filename]; } else { - if (in_array($name . '.b64', $reqfiles)) { - $files [$name . '.b64'] = base64_encode($data); - } else { - $files [$name] = $data; + $name = $mform->get_new_filename( $field ); + $data = $mform->get_file_content( $field ); + if ($data !== false && $name !== false) { + // Autodetect text file encode if not binary. + if (! vpl_is_binary( $name )) { + $encode = mb_detect_encoding( $data, 'UNICODE, UTF-16, UTF-8, ISO-8859-1', true ); + if ($encode > '') { // If code detected. + $data = iconv( $encode, 'UTF-8', $data ); + } + $files [$name] = $data; + } else { + if (in_array($name . '.b64', $reqfiles)) { + $files [$name . '.b64'] = base64_encode($data); + } else { + $files [$name] = $data; + } + } } } } diff --git a/forms/submission_form.php b/forms/submission_form.php index 6096ec5e2911568d0a35390f1bdf7e5e5c1590b4..1537cdb448690cf36b73c4fd23bfc68895d25932 100644 --- a/forms/submission_form.php +++ b/forms/submission_form.php @@ -28,20 +28,22 @@ defined( 'MOODLE_INTERNAL' ) || die(); global $CFG; require_once($CFG->libdir.'/formslib.php'); require_once(dirname(__FILE__).'/../locallib.php'); +require_once(dirname(__FILE__).'/edit.class.php'); class mod_vpl_submission_form extends moodleform { protected $vpl; + protected $userid; protected function getinternalform() { return $this->_form; } - public function __construct($page, $vpl) { + public function __construct($page, $vpl, $userid) { $this->vpl = $vpl; + $this->userid = $userid; parent::__construct( $page ); } protected function definition() { global $CFG; $mform = & $this->_form; - $mform->addElement( 'header', 'headersubmission', get_string( 'submission', VPL ) ); // Identification info. $mform->addElement( 'hidden', 'id' ); $mform->setType( 'id', PARAM_INT ); @@ -54,18 +56,85 @@ class mod_vpl_submission_form extends moodleform { ) ); $mform->setType( 'comments', PARAM_TEXT ); + $firstsub = ($this->vpl->last_user_submission( $this->userid ) === false); + + $mform->addElement( 'select', 'submitmethod', get_string( 'submitmethod', VPL ), + array('archive' => get_string( 'archive', VPL ), 'files' => get_string( 'files' )) ); + + $mform->addElement( 'header', 'headersubmitarchive', get_string( 'submitarchive', VPL ) ); + + if (!$firstsub) { + $mform->addElement( 'radio', 'archiveaction', get_string( 'submitarchive', VPL ), + get_string( 'archivereplacedelete', VPL ), 'replacedelete'); + $mform->addElement( 'radio', 'archiveaction', '', + get_string( 'archivereplace', VPL ), 'replace' ); + $mform->disabledIf( 'archiveaction', 'submitmethod', 'neq', 'archive' ); + } + $mform->addElement( 'filepicker', 'archive', null, null, array('accepted_types' => '.zip') ); + $mform->disabledIf( 'archive', 'submitmethod', 'neq', 'archive' ); + + $mform->addElement( 'header', 'headersubmitfiles', get_string( 'submitfiles', VPL ) ); + // Files upload. $instance = $this->vpl->get_instance(); - $files = $this->vpl->get_files('required'); - $nfiles = count( $files ); - for ($i = 0; $i < $instance->maxfiles; $i ++) { + $reqfiles = $this->vpl->get_files('required'); + $i = 0; + foreach ($reqfiles as $reqfile) { $field = 'file' . $i; - if ($i < $nfiles) { - $mform->addElement( 'filepicker', $field, $files [$i] ); - } else { - $mform->addElement( 'filepicker', $field, get_string( 'anyfile', VPL ) ); + if (!$firstsub) { + $mform->addElement( 'radio', $field . 'action', $reqfile, + get_string( 'keepcurrentfile', VPL ), 'keep'); + $mform->addElement( 'radio', $field . 'action', '', + get_string( 'replacefile', VPL ), 'replace' ); + $mform->disabledIf( $field . 'action', 'submitmethod', 'neq', 'files' ); } + $mform->addElement( 'filepicker', $field ); + $mform->disabledIf( $field, 'submitmethod', 'neq', 'files' ); + if (!$firstsub) { + $mform->disabledIf( $field, $field . 'action', 'neq', 'replace' ); + } + $i++; + } + $submission = $this->vpl->last_user_submission( $this->userid ); + if ($submission !== false) { + $subfiles = (new mod_vpl_submission( $this->vpl, $submission ))->get_submitted_fgm()->getFileList(); + foreach ($subfiles as $subfile) { + if (!in_array($subfile, $reqfiles)) { + $field = 'file' . $i; + if (!$firstsub) { + $mform->addElement( 'radio', $field . 'action', $subfile, get_string( 'keepcurrentfile', VPL ), 'keep'); + $mform->addElement( 'radio', $field . 'action', '', get_string( 'deletefile', VPL ), 'delete' ); + $mform->addElement( 'radio', $field . 'action', '', get_string( 'replacefile', VPL ), 'replace' ); + $mform->disabledIf( $field . 'action', 'submitmethod', 'neq', 'files' ); + $mform->addElement( 'hidden', $field . 'name', $subfile ); + $mform->setType( $field . 'name', PARAM_RAW ); + } + $mform->addElement( 'filepicker', $field ); + $mform->disabledIf( $field, 'submitmethod', 'neq', 'files' ); + if (!$firstsub) { + $mform->disabledIf( $field, $field . 'action', 'neq', 'replace' ); + } + $i++; + } + } + } + + while ($i < $instance->maxfiles) { + $field = 'file' . $i; + $mform->addElement( 'filepicker', $field, get_string( 'anyfile', VPL ) ); + $mform->disabledIf( $field, 'submitmethod', 'neq', 'files' ); + $i++; } $this->add_action_buttons( true, get_string( 'submit' ) ); + + global $PAGE; + $PAGE->requires->js_call_amd('mod_vpl/submissionform', 'setup'); + } + public function set_data($data) { + for($i=0; $i < $this->vpl->get_instance()->maxfiles; $i++) { + $data->{'file'.$i.'action'} = 'keep'; + $data->{'archiveaction'} = 'replacedelete'; + } + parent::set_data($data); } } diff --git a/lang/en/vpl.php b/lang/en/vpl.php index 19b8ab3b6b47ee9a9d87a16f30481c551084b2f1..848174cc552706afaa131e4e37bb081dd241da43 100644 --- a/lang/en/vpl.php +++ b/lang/en/vpl.php @@ -28,6 +28,9 @@ $string ['allfiles'] = 'All files'; $string ['allowshowprevious'] = 'Allow student show previous submissions'; $string ['allsubmissions'] = 'All submissions'; $string ['anyfile'] = 'Any file'; +$string ['archive'] = 'Archive'; +$string ['archivereplace'] = 'Replace only files present in archive'; +$string ['archivereplacedelete'] = 'Replace all files and delete files not present in archive'; $string ['attemptnumber'] = 'Attempt number {$a}'; $string ['autodetect'] = 'Autodetect'; $string ['automaticevaluation'] = 'Automatic evaluation'; @@ -80,6 +83,7 @@ $string ['delete'] = 'Delete'; $string ['delete_file_fq'] = "delete '{\$a}' file?"; $string ['delete_file_q'] = 'Delete file?'; $string ['deleteallsubmissions'] = 'Delete all submissions'; +$string ['deletefile'] = 'Delete file'; $string ['description'] = 'Description'; $string ['diff'] = 'diff'; $string ['discard_submission_period'] = 'Discard submission period'; @@ -159,6 +163,7 @@ $string ['jail_servers'] = 'Execution servers list'; $string ['jail_servers_config'] = 'Execution servers config'; $string ['jail_servers_description'] = 'Write a line for each server'; $string ['joinedfiles'] = 'Joined selected files'; +$string ['keepcurrentfile'] = 'Keep current file'; $string ['keepfiles'] = 'Files to keep when running'; $string ['keyboard'] = 'Keyboard'; $string ['lasterror'] = 'Last error info'; @@ -252,6 +257,7 @@ $string ['removegrade'] = 'Remove grade'; $string ['rename'] = 'Rename'; $string ['rename_file'] = 'Rename file'; $string ['replace_find'] = 'Replace/Find'; +$string ['replacefile'] = 'Replace'; $string ['replacenewer'] = "A newer version was already saved.\nDo you want to replace the newer version with this one?"; $string ['requestedfiles'] = 'Requested files'; $string ['requirednet'] = 'Allowed submission from net'; @@ -301,6 +307,9 @@ $string ['submissionscharts'] = 'Submissions charts'; $string ['submissionselection'] = 'Submission selection'; $string ['submissionslist'] = 'Submissions list'; $string ['submissionview'] = 'Submission view'; +$string ['submitarchive'] = 'Submit archive'; +$string ['submitfiles'] = 'Submit files'; +$string ['submitmethod'] = 'Submit method'; $string ['submittedby'] = 'Submitted by {$a}'; $string ['submittedon'] = 'Submitted on'; $string ['submittedonp'] = 'Submitted on {$a}';