From bd053ee693a279a255896f5ae224bd7dbb229b2a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Franti=C5=A1ek=20Gal=C4=8D=C3=ADk?=
Each variation has an identification code and a description. The identification code is used by the vpl_enviroment.sh file to pass
the variation assigned to each student to the script files. The description, formatted in HTML, is shown to the students that have assigned
the corresponding variation.' . get_string( 'executionfiles', VPL ) . "
\n";
$fe->print_files( false );
}
+
+ // print names of output files defined for this lab
+ $output_files = $vpl->get_output_files();
+ if (count($output_files) > 0) {
+ echo ''.get_string('outputfiles', VPL)."
\n";
+ echo '';
+ foreach ($output_files as $filename) {
+ // distinguish between hidden and normal files
+ if (substr(basename($filename), 0, 1) == '.') {
+ echo '
';
+ }
}
// Finish the page.
if (vpl_get_webservice_available()) {
diff --git a/views/downloadoutputfile.php b/views/downloadoutputfile.php
new file mode 100644
index 00000000..86e643b9
--- /dev/null
+++ b/views/downloadoutputfile.php
@@ -0,0 +1,96 @@
+.
+
+/**
+ * Download an output file
+ *
+ * @package mod_vpl
+ * @copyright 2016 Frantisek Galcik
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @author Frantisek Galcik ' . get_string( 'automaticevaluation', VPL ) . $div->generate( true ) . '
';
+
+ $ce_html = $this->get_ce_html($ce, true, true);
+ $outputfiles = $this->get_ce_output_files_html();
+
+ $show_evaluation = false;
+ $show_evaluation |= strlen($ce_html->compilation) > 0;
+ $show_evaluation |= strlen($ce_html->execution) > 0;
+ $show_evaluation |= strlen($ce_html->grade) > 0;
+ $show_evaluation |= strlen($ce_html->checklist) > 0;
+ $show_evaluation |= strlen($outputfiles) > 0;
+
+ if($show_evaluation){
+ $div = new vpl_hide_show_div(!$this->is_graded() || !$this->vpl->get_visiblegrade());
+ echo ''.get_string('automaticevaluation',VPL).$div->generate(true).'
';
$div->begin_div();
echo $OUTPUT->box_start();
- if (strlen( $grade ) > 0) {
- echo '' . $grade . '
';
+ if(strlen($ce_html->grade)>0){
+ echo ''.$ce_html->grade.'
';
}
- if (strlen( $compilation ) > 0) {
- echo $compilation;
+ if(strlen($ce_html->compilation)>0){
+ echo $ce_html->compilation;
}
- if (strlen( $execution ) > 0) {
- echo $execution;
+ if(strlen($ce_html->execution)>0){
+ echo $ce_html->execution;
}
+ if (strlen($ce_html->checklist)>0) {
+ echo $ce_html->checklist;
+ }
+ if (strlen($outputfiles)>0){
+ echo $outputfiles;
+ }
+
echo $OUTPUT->box_end();
$div->end_div();
}
}
+ private function get_ce_output_files_html() {
+ $fgm = $this->get_output_files_fgm();
+ $output_files = $fgm->getFileList();
+ $downloadable_files = array();
+ $is_grader = $this->vpl->has_capability(VPL_GRADE_CAPABILITY);
+ foreach ($output_files as $output_file) {
+ $is_hidden = (substr(basename($output_file), 0, 1) == '.');
+ if ($is_grader || !$is_hidden) {
+ $downloadable_files[] = $output_file;
+ }
+ }
+
+ if (count($downloadable_files) == 0) {
+ return '';
+ }
+
+ $id = $this->vpl->get_course_module()->id;
+ $user_id = $this->instance->userid;
+ $submission_id = $this->instance->id;
+
+ $ret = '';
+ $ret .= ''.get_string('outputfiles', VPL).'
'."\n";
+ $ret .= '';
+ foreach ($downloadable_files as $file) {
+ $url = vpl_mod_href('views/downloadoutputfile.php', 'id', $id, 'userid', $user_id, 'submissionid', $submission_id, 'file', $file);
+ $fs = $fgm->get_file_size($file);
+ if ($fs >= 0) {
+ $ret .= '
';
+
+ return $ret;
+ }
+
/**
* Print sudmission
*/
@@ -674,6 +759,8 @@ public function print_submission() {
const COMMENTTAG = 'Comment :=>>';
const BEGINCOMMENTTAG = '<|--';
const ENDCOMMENTTAG = '--|>';
+ const CHECKLISTTAG = 'Checklist :=>>';
+
public function proposedgrade($text) {
$ret = '';
$nl = vpl_detect_newline( $text );
@@ -686,6 +773,9 @@ public function proposedgrade($text) {
return $ret;
}
public function proposedcomment($text) {
+ $parsed_execution = $this->parse_execution($text);
+ return $parsed_execution->comments;
+ /*
$incomment = false;
$ret = '';
$nl = vpl_detect_newline( $text );
@@ -708,6 +798,70 @@ public function proposedcomment($text) {
}
}
return $ret;
+ */
+ }
+
+ /**
+ * Parses raw execution.
+ * @param $text string the raw execution result
+ * @return string execution result without lines with/in tags.
+ */
+ function parse_execution($text) {
+ $ret = new stdClass();
+ $ret->grade = '';
+ $ret->comments = '';
+ $ret->checklist = array();
+ $ret->execution = '';
+
+ $nl = vpl_detect_newline($text);
+ $lines = explode($nl,$text);
+
+ $closing_tag = false;
+ $tagPairs = array(self::GRADETAG => false, self::COMMENTTAG => false, self::CHECKLISTTAG => false, self::BEGINCOMMENTTAG => self::ENDCOMMENTTAG);
+ foreach($lines as $line){
+ $line = rtrim($line);
+ $tline = trim($line);
+ if($closing_tag !== false) {
+ // we are in a block tag
+ if ($tline === $closing_tag) {
+ $closing_tag = false;
+ } else {
+ // handle line in a block tag
+ if ($closing_tag === self::ENDCOMMENTTAG) {
+ $ret->comments .= $line."\n";
+ }
+ }
+ }else{
+ // detect presence of opening tag
+ $opening_tag = false;
+ foreach ($tagPairs as $opening => $closing) {
+ if (substr($line, 0, strlen($opening)) === $opening) {
+ $opening_tag = $opening;
+ $closing_tag = $closing;
+ break;
+ }
+ }
+
+ // remove opening tag from line when found
+ if ($opening_tag !== false) {
+ $line = substr($line, strlen($opening_tag));
+ }
+
+ // handle line according to found tag
+ if ($opening_tag === false) {
+ $ret->execution .= $line."\n";
+ } elseif ($opening_tag === self::COMMENTTAG) {
+ $ret->comments .= $line."\n";
+ } elseif ($opening_tag === self::CHECKLISTTAG) {
+ $ret->checklist[] = $line;
+ } elseif ($opening_tag === self::GRADETAG) {
+ if ($ret->grade == '') {
+ $ret->grade = $line;
+ }
+ }
+ }
+ }
+ return $ret;
}
/**
@@ -919,6 +1073,17 @@ public function savece($result) {
if ($result ['executed'] > 0) {
file_put_contents( $execfn, $result ['execution'] );
}
+
+ if(isset($result['outputfiles'])) {
+ $fgm = $this->get_output_files_fgm();
+ foreach ($result['outputfiles'] as $filename => $content) {
+ if (is_string($content)) {
+ $fgm->addFile($filename, $content);
+ } else if (is_object($content)) {
+ $fgm->addFile($filename, $content->scalar);
+ }
+ }
+ }
}
/**
@@ -944,58 +1109,61 @@ public function getce() {
return $ret;
}
- /**
- * Get compilation, execution and proposed grade from array
- *
- * @param $response array
- * response from server
- * @param
- * $compilation
- * @param
- * $execution
- * @param
- * $grade
- * @return void
- */
- public function get_ce_html($response, &$compilation, &$execution, &$grade, $dropdown, $returnrawexecution = false) {
- $compilation = '';
- $execution = '';
- $grade = '';
- if ($response ['compilation']) {
- $compilation = $this->result_to_html( $response ['compilation'], $dropdown );
- if (strlen( $compilation )) {
- $compilation = '' . get_string( 'compilation', VPL ) . '
' . $compilation;
+ public function get_ce_html($response, $dropdown, $returnrawexecution=false){
+ $ret = new stdClass();
+ $ret->compilation = '';
+ $ret->execution = '';
+ $ret->grade = '';
+ $ret->checklist = '';
+
+ if($response['compilation']){
+ $ret->compilation = $this->result_to_html($response['compilation'],$dropdown);
+ if(strlen($ret->compilation)>0){
+ $ret->compilation =''.get_string('compilation',VPL).'
'.$ret->compilation;
}
}
- if ($response ['executed'] > 0) {
- $rawexecution = $response ['execution'];
- $proposedcomments = $this->proposedcomment( $rawexecution );
- $proposedgrade = $this->proposedgrade( $rawexecution );
- $execution = $this->result_to_html( $proposedcomments, $dropdown );
- if (strlen( $execution )) {
- $execution = '' . get_string( 'comments', VPL ) . "
\n" . $execution;
+
+ if($response['executed']>0){
+ $raw_execution = $response['execution'];
+ $parsed_execution = $this->parse_execution($raw_execution);
+ $proposed_comments = $parsed_execution->comments;
+ $proposed_grade = $parsed_execution->grade;
+ $execution=$this->result_to_HTML($proposed_comments,$dropdown);
+ if(strlen($execution)>0){
+ $execution = ''.get_string('comments',VPL)."
\n".$execution;
}
- if (strlen( $proposedgrade )) {
- $sgrade = $this->print_grade_core( $proposedgrade );
- $grade = get_string( 'proposedgrade', VPL, $sgrade );
+ if(strlen($proposed_grade)>0){
+ $sgrade = $this->print_grade_core($proposed_grade);
+ $ret->grade = get_string('proposedgrade',VPL,$sgrade);
}
- // Show raw ejecution if no grade or comments.
- if (strlen( $rawexecution ) > 0 && (strlen( $execution ) + strlen( $proposedgrade ) == 0)) {
- $execution .= "
\n";
- $execution .= '' . get_string( 'execution', VPL ) . "
\n";
- $execution .= '' . s( $rawexecution ) . '
';
- } else if ($returnrawexecution && strlen( $rawexecution ) > 0
- && ($this->vpl->has_capability( VPL_MANAGE_CAPABILITY ))) {
- // Show raw ejecution if manager and $returnrawexecution.
+
+ if (count($parsed_execution->checklist)>0) {
+ $ret->checklist = $this->get_checklist_html($parsed_execution->checklist);
+ }
+
+ // show raw ejecution if no grade or comments
+ if(strlen($raw_execution)>0 &&
+ (strlen($execution)+strlen($proposed_grade)==0) ){
+ $execution .="
\n";
+ $execution .=''.get_string('execution',VPL)."
\n";
+ $execution .= ''.s($parsed_execution->execution).'
';
+ } // show raw ejecution if manager and $returnrawexecution
+ elseif($returnrawexecution && strlen($raw_execution)>0 &&
+ ($this->vpl->has_capability(VPL_MANAGE_CAPABILITY))){
$div = new vpl_hide_show_div();
- $execution .= "
\n";
- $execution .= '' . get_string( 'execution', VPL ) . $div->generate( true ) . "
\n";
- $execution .= $div->begin_div( true );
- $execution .= '' . s( $rawexecution ) . '
';
- $execution .= $div->end_div( true );
+ $execution .="
\n";
+ $execution .=''.get_string('execution',VPL).$div->generate(true)."
\n";
+ $execution .=$div->begin_div(true);
+ $execution .= ''.s($raw_execution).'
';
+ $execution .=$div->end_div(true);
}
+
+ $ret->execution = $execution;
}
+
+ return $ret;
}
+
public function get_ce_for_editor($response = null) {
$ce = new stdClass();
$ce->compilation = '';
@@ -1010,8 +1178,10 @@ public function get_ce_for_editor($response = null) {
}
if ($response ['executed'] > 0) {
$rawexecution = $response ['execution'];
- $evaluation = $this->proposedcomment( $rawexecution );
- $proposedgrade = $this->proposedgrade( $rawexecution );
+ $parsed_execution = $this->parse_execution($rawexecution);
+ $evaluation = $parsed_execution->comments;
+ $proposedgrade = $parsed_execution->grade;
+
$ce->evaluation = $evaluation;
// TODO Important what to show to students about grade.
if (strlen( $proposedgrade ) && $this->vpl->get_instance()->grade) {
@@ -1020,7 +1190,11 @@ public function get_ce_for_editor($response = null) {
}
// Show raw ejecution if no grade or comments.
$manager = $this->vpl->has_capability( VPL_MANAGE_CAPABILITY );
- if ((strlen( $rawexecution ) > 0 && (strlen( $evaluation ) + strlen( $proposedgrade ) == 0)) || $manager) {
+ if ((strlen( $rawexecution ) > 0 && (strlen( $evaluation ) + strlen( $proposedgrade ) == 0)) && !$manager) {
+ $ce->execution = $parsed_execution->execution;
+ }
+
+ if ($manager) {
$ce->execution = $rawexecution;
}
}
@@ -1043,17 +1217,135 @@ public function get_detail() {
}
public function get_ce_parms() {
$response = $this->getce();
- $this->get_ce_html( $response, $compilation, $execution, $grade, false );
+ $ce_html = $this->get_ce_html($response, false);
$params = '';
- if (strlen( $compilation )) {
- $params .= vpl_param_tag( 'compilation', $compilation );
+ if (strlen( $ce_html->compilation )) {
+ $params .= vpl_param_tag( 'compilation', $ce_html->compilation );
}
- if (strlen( $execution )) {
- $params .= vpl_param_tag( 'evaluation', $execution );
+ if (strlen( $ce_html->execution )) {
+ $params .= vpl_param_tag( 'evaluation', $ce_html->execution );
}
- if (strlen( $grade )) {
- $params .= vpl_param_tag( 'grade', $grade );
+ if (strlen( $ce_html->grade )) {
+ $params .= vpl_param_tag( 'grade', $ce_html->grade );
}
return $params;
}
+
+ /**
+ * Returns checklist transformed to html.
+ * @param $checklist array items of generated checklist
+ * @return string checklist formatted as html
+ */
+ private function get_checklist_html($checklist) {
+ // each checklist line has format: type > details
+ // types: group (named group of checklist items - test), test (a test),
+ // error (error message related to the last test)
+ // warning (warning message related to the last test)
+ // note (information message related to the last test)
+ // internal (information message related to the last test which is available only for graders)
+ // OK (indicates that the last test passed)
+ // FAILED (indicates that the last test failed)
+
+ $is_grader = $this->vpl->has_capability(VPL_GRADE_CAPABILITY);
+
+ // build checklist tree
+ $message_types = array('error', 'warning', 'note', 'internal');
+ $groups = array();
+ $current_group = null;
+ $current_test = null;
+ foreach ($checklist as $line) {
+ $details = '';
+ $separator = strpos($line, '>');
+ if ($separator === false) {
+ $type = trim($line);
+ } else {
+ $type = trim(substr($line, 0, $separator));
+ $details = trim(substr($line, $separator+1));
+ }
+
+ // ensure group
+ if (($type === 'group') || is_null($current_group)) {
+ $current_group = new stdClass();
+ $current_group->title = '';
+ $current_group->tests = array();
+ $groups[] = $current_group;
+ $current_test = null;
+ }
+
+ if ($type === 'group') {
+ $current_group->title = $details;
+ continue;
+ }
+
+ // ensure test
+ if (($type === 'test') || is_null($current_test)) {
+ $current_test = new stdClass();
+ $current_test->title = '';
+ $current_test->messages = array();
+ $current_test->status = false;
+ $current_group->tests[] = $current_test;
+ }
+
+ if ($type == 'test') {
+ $current_test->title = $details;
+ continue;
+ }
+
+ if ($type === 'OK') {
+ $current_test->status = true;
+ continue;
+ }
+
+ if ($type === 'FAILED') {
+ $current_test->status = false;
+ continue;
+ }
+
+ if (in_array($type, $message_types)) {
+ $message = new stdClass();
+ $message->type = $type;
+ $message->content = $details;
+ $current_test->messages[] = $message;
+ }
+ }
+
+ // generate html
+ $ret = '';
+ foreach ($groups as $group) {
+ if (count($group->tests) == 0) {
+ continue;
+ }
+
+ $table = new html_table();
+ $table->caption = s($group->title);
+ $table->align = array ('left', 'right');
+ $table->data = array();
+
+ foreach ($group->tests as $test) {
+ $messages = '';
+ foreach ($test->messages as $message) {
+ if (($message->type !== 'internal') || (($message->type === 'internal') && $is_grader)) {
+ $messages .= ''.$messages.'
';
+ }
+
+ if ($test->status) {
+ $status_html = ''.get_string('test_ok', VPL).'';
+ } else {
+ $status_html = ''.get_string('test_failed', VPL).'';
+ }
+
+ $table->data[] = array(s($test->title).$messages, $status_html);
+ }
+
+ $ret .= html_writer::table($table);
+ }
+
+ return $ret;
+ }
+
}
diff --git a/vpl_submission_CE.class.php b/vpl_submission_CE.class.php
index 3017eb40..c088bb32 100644
--- a/vpl_submission_CE.class.php
+++ b/vpl_submission_CE.class.php
@@ -313,10 +313,16 @@ public function prepare_execution($type, &$already = array(), $vpl = null) {
$data->files ['vpl_environment.sh'] = $info;
$data->files ['common_script.sh'] = file_get_contents( dirname( __FILE__ ) . '/jail/default_scripts/common_script.sh' );
- // TODO change jail server to avoid this patch.
+ // TODO change jail server to avoid this patch (NOTE: can be removed as jail server fixes it)
if (count( $data->filestodelete ) == 0) { // If keeping all files => add dummy.
$data->filestodelete ['__vpl_to_delete__'] = 1;
}
+
+ // Add names of output files
+ foreach ($vpl->get_output_files() as $filename) {
+ $data->outputfiles [$filename] = 1;
+ }
+
// Info to log who/what.
$data->userid = $this->instance->userid;
$data->activityid = $this->vpl->get_instance()->id;
@@ -445,8 +451,9 @@ public function retrieveresult() {
// If automatic grading.
if ($this->vpl->get_instance()->automaticgrading) {
$data = new StdClass();
- $data->grade = $this->proposedGrade( $response ['execution'] );
- $data->comments = $this->proposedComment( $response ['execution'] );
+ $parsed_execution = $this->parse_execution( $response['execution'] );
+ $data->grade = $parsed_execution->grade;
+ $data->comments = $parsed_execution->comments;
$this->set_grade( $data, true );
}
}
From 51b38bc7bd6c27bb07e3e2af050dbdc7042a1a87 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Franti=C5=A1ek=20Gal=C4=8D=C3=ADk?=
";
+ break;
+ }
+ $files [$name] = $data;
} else {
- if ($i < $minfiles) { // Add empty file if required.
- $files [] = array (
- 'name' => '',
- 'data' => ''
- );
+ // if required file is missing, add the file with undefined content.
+ if ($i < $minfiles) {
+ $files [$required_files[$i]] = null;
}
}
}
- $errormessage = '';
- if ($subid = $vpl->add_submission( $userid, $files, $fromform->comments, $errormessage )) {
+ if ((strlen($errormessage) == 0) && ($subid = $vpl->add_submission( $userid, $files, $fromform->comments, $errormessage ))) {
\mod_vpl\event\submission_uploaded::log( array (
'objectid' => $subid,
'context' => $vpl->get_context(),
diff --git a/lang/en/vpl.php b/lang/en/vpl.php
index 3c96ef13..58eccfa6 100644
--- a/lang/en/vpl.php
+++ b/lang/en/vpl.php
@@ -414,20 +414,22 @@
the variation assigned to each student to the script files. The description, formatted in HTML, is shown to the students that have assigned
the corresponding variation.