Commit 812cd760 authored by Kurzenberger's avatar Kurzenberger
Browse files

deployed recommendations

1 merge request!1Coding style and recommendations
Showing with 466 additions and 355 deletions
+466 -355
No preview for this file type
...@@ -32,6 +32,26 @@ class DbUtils { ...@@ -32,6 +32,26 @@ class DbUtils {
*/ */
private const TABLE_RESULT = "assignsubmission_dta_result"; private const TABLE_RESULT = "assignsubmission_dta_result";
private const TABLE_RECOMMENDATIONS = "assignsubmission_dta_recommendations";
/**
* Gets the recommendations for a given submission.
*
* @param int $submissionid ID of the submission
* @return array list of recommendations
*/
public static function get_recommendations_from_database(int $assignmentid,int $submissionid ): array {
global $DB;
// Query the database to get all recommendations for the given submission id.
$records = $DB->get_records(self::TABLE_RECOMMENDATIONS, [
'assignment_id' => $assignmentid,
'submission_id' => $submissionid,
]);
return $records;
}
/** /**
* gets summary with all corresponding result entries * gets summary with all corresponding result entries
* *
...@@ -83,6 +103,52 @@ class DbUtils { ...@@ -83,6 +103,52 @@ class DbUtils {
return $summary; return $summary;
} }
public static function storeRecommendationstoDatabase(
int $assignmentid,
int $submissionid,
array $recommendations
): void {
global $DB;
error_log(print_r($recommendations,true));
// Prepare recommendations to persist to array.
$recommendationrecords = [];
foreach ($recommendations as $recommendation) {
$record = new stdClass();
$record->assignment_id = $assignmentid;
$record->submission_id = $submissionid;
$record->topic = $recommendation['topic'];
$record->url = $recommendation['url'];
$record->exercise_name = $recommendation['exercise_name'];
$record->difficulty = $recommendation['difficulty'];
$record->score = $recommendation['score'];
$recommendationrecords[] = $record;
}
error_log("Das sind die Recommendationrecords.");
error_log(print_r($recommendationrecords,true));
// If recommendations already exist, delete old values beforehand.
$existingrecords = $DB->get_record('assignsubmission_dta_recommendations', [
'assignment_id' => $assignmentid,
'submission_id' => $submissionid,
]);
if ($existingrecords) {
$DB->delete_records('assignsubmission_dta_recommendations', [
'assignment_id' => $assignmentid,
'submission_id' => $submissionid,
]);
}
// Create new recommendation entries.
foreach ($recommendationrecords as $rec) {
error_log("Insert record");
error_log(print_r($rec,true));
$DB->insert_record('assignsubmission_dta_recommendations', $rec);
}
}
/** /**
* save given result summary and single results to database * save given result summary and single results to database
...@@ -107,8 +173,7 @@ class DbUtils { ...@@ -107,8 +173,7 @@ class DbUtils {
$summaryrecord->global_stacktrace = $summary->globalstacktrace; $summaryrecord->global_stacktrace = $summary->globalstacktrace;
$summaryrecord->successful_competencies = $summary->successfultestcompetencies; $summaryrecord->successful_competencies = $summary->successfultestcompetencies;
$summaryrecord->tested_competencies = $summary->overalltestcompetencies; $summaryrecord->tested_competencies = $summary->overalltestcompetencies;
$summaryrecord->recommendations = $summary->recommendations;
// Prepare results to persist to array. // Prepare results to persist to array.
$resultrecords = []; $resultrecords = [];
foreach ($summary->results as $r) { foreach ($summary->results as $r) {
...@@ -161,6 +226,8 @@ class DbUtils { ...@@ -161,6 +226,8 @@ class DbUtils {
$DB->delete_records(self::TABLE_RESULT, null); $DB->delete_records(self::TABLE_RESULT, null);
$DB->delete_records(self::TABLE_SUMMARY, null); $DB->delete_records(self::TABLE_SUMMARY, null);
$DB->delete_records(self::TABLE_RECOMMENDATIONS, null);
} }
} }
...@@ -57,7 +57,6 @@ class provider implements \core_privacy\local\metadata\provider, ...@@ -57,7 +57,6 @@ class provider implements \core_privacy\local\metadata\provider,
'global_stacktrace' => 'privacy:metadata:assignsubmission_dta_summary:global_stacktrace', 'global_stacktrace' => 'privacy:metadata:assignsubmission_dta_summary:global_stacktrace',
'successful_competencies' => 'privacy:metadata:assignsubmission_dta_summary:successful_competencies', 'successful_competencies' => 'privacy:metadata:assignsubmission_dta_summary:successful_competencies',
'tested_competencies' => 'privacy:metadata:assignsubmission_dta_summary:tested_competencies', 'tested_competencies' => 'privacy:metadata:assignsubmission_dta_summary:tested_competencies',
'recommendations' => 'privacy:metadata:assignsubmission_dta_summary:recommendations',
], ],
'privacy:metadata:assignsubmission_dta_summary' 'privacy:metadata:assignsubmission_dta_summary'
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
* *
* @package assignsubmission_dta * @package assignsubmission_dta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @copyright Gero Lueckemeyer and student project teams
*/ */
class view_submission_utils { class view_submission_utils {
...@@ -85,342 +84,318 @@ class view_submission_utils { ...@@ -85,342 +84,318 @@ class view_submission_utils {
} }
/** /**
* generates detailed view html * Generiert die detaillierte HTML-Ansicht, einschließlich Zusammenfassung, Kompetenzen, Details und Empfehlungen.
* *
* @param int $assignmentid assignment * @param int $assignmentid Assignment-ID
* @param int $submissionid submission to create a report for * @param int $submissionid Submission-ID, für die der Bericht erstellt wird
*/ * @return string HTML-Code
public static function generatedetailhtml( */
int $assignmentid, public static function generatedetailhtml(
int $submissionid int $assignmentid,
): string { int $submissionid
): string {
// Fetch data.
$summary = DbUtils::getResultSummaryFromDatabase($assignmentid, $submissionid); // HTML-Inhalt initialisieren
$html = ""; $html = "";
// Define a few css classes and prepare html attribute arrays to beautify the output. // Daten abrufen
$tableheaderrowattributes = ["class" => "dtaTableHeaderRow"]; $summary = DbUtils::getResultSummaryFromDatabase($assignmentid, $submissionid);
$tablerowattributes = ["class" => "dtaTableRow"];
$resultrowattributes = $tablerowattributes; // CSS-Klassen und HTML-Attributarrays definieren
$unknownattributes = 'dtaResultUnknown'; $tableheaderrowattributes = ["class" => "dtaTableHeaderRow"];
$successattributes = 'dtaResultSuccess'; $tablerowattributes = ["class" => "dtaTableRow"];
$failureattributes = 'dtaResultFailure'; $attributes = ["class" => "dtaTableData"];
$compilationerrorattributes = 'dtaResultCompilationError'; $unknownattributes = 'dtaResultUnknown';
$successattributes = 'dtaResultSuccess';
// Summary table. $failureattributes = 'dtaResultFailure';
$tmp = ""; $compilationerrorattributes = 'dtaResultCompilationError';
$tmp .= html_writer::tag("th", get_string("summary", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]);
$tmp .= html_writer::empty_tag("th", ["class" => "dtaTableHeader"]); // **Zusammenfassungstabelle erstellen**
$header = html_writer::tag("tr", $tmp, $tableheaderrowattributes); // Kopfzeile
$header = html_writer::tag("thead", $header); $tmp = "";
$tmp .= html_writer::tag("th", get_string("summary", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]);
$tmp .= html_writer::empty_tag("th", ["class" => "dtaTableHeader"]);
$header = html_writer::tag("tr", $tmp, $tableheaderrowattributes);
$header = html_writer::tag("thead", $header);
// Tabellenkörper
$body = "";
// Gesamtanzahl
$tmp = "";
$tmp .= html_writer::tag("td", get_string("total_items", self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::tag("td", $summary->resultCount(), $attributes);
$resultrowattributes = $tablerowattributes;
$resultrowattributes['class'] .= " " . $unknownattributes;
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
// Erfolgreiche Tests
$tmp = "";
$tmp .= html_writer::tag("td", get_string("tests_successful", self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::tag("td", $summary->successfulCount(), $attributes);
$resultrowattributes = $tablerowattributes;
$successrate = "?";
if ($summary->unknownCount() > 0 || $summary->compilationErrorCount() > 0) {
$resultrowattributes['class'] .= " " . $unknownattributes;
} else {
$successrate = round(($summary->successfulCount() / $summary->resultCount()) * 100, 2 );
if ($successrate < 50) {
$resultrowattributes['class'] .= " " . $compilationerrorattributes;
} else if ($successrate < 75) {
$resultrowattributes['class'] .= " " . $failureattributes;
} else {
$resultrowattributes['class'] .= " " . $successattributes;
}
}
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
// Fehlgeschlagene Tests
$tmp = "";
$tmp .= html_writer::tag("td", get_string("failures", self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::tag("td", $summary->failedCount(), $attributes);
$resultrowattributes = $tablerowattributes;
if ($summary->failedCount() > 0) {
$resultrowattributes['class'] .= " " . $failureattributes;
} else {
$resultrowattributes['class'] .= " " . $successattributes;
}
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
// Kompilierungsfehler
$tmp = "";
$tmp .= html_writer::tag("td", get_string("compilation_errors", self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::tag("td", $summary->compilationErrorCount(), $attributes);
$resultrowattributes = $tablerowattributes;
if ($summary->compilationErrorCount() > 0) {
$resultrowattributes['class'] .= " " . $compilationerrorattributes;
} else {
$resultrowattributes['class'] .= " " . $successattributes;
}
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
// Unbekannter Status
$tmp = "";
$tmp .= html_writer::tag("td", get_string("unknown_state", self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::tag("td", $summary->unknownCount(), $attributes);
$resultrowattributes = $tablerowattributes;
if ($summary->unknownCount() > 0) {
$resultrowattributes['class'] .= " " . $unknownattributes;
} else {
$resultrowattributes['class'] .= " " . $successattributes;
}
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
// Erfolgsrate
$tmp = "";
$tmp .= html_writer::tag("td", html_writer::tag("b", get_string("success_rate", self::COMPONENT_NAME)), $attributes);
$tmp .= html_writer::tag(
"td",
html_writer::tag("b", $summary->successfulCount()
. "/" . (($summary->compilationErrorCount() == 0 && $summary->unknownCount() == 0) ? $summary->resultCount()
. " (" . $successrate . "%)"
: "?")),
$attributes);
$resultrowattributes = $tablerowattributes;
if ($summary->unknownCount() > 0 || $summary->compilationErrorCount() > 0) {
$resultrowattributes['class'] .= " " . $unknownattributes;
} else {
if ($successrate < 50) {
$resultrowattributes['class'] .= " " . $compilationerrorattributes;
} else if ($successrate < 75) {
$resultrowattributes['class'] .= " " . $failureattributes;
} else {
$resultrowattributes['class'] .= " " . $successattributes;
}
}
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
$body = ""; // Tabelle zusammenstellen
$tmp = ""; $body = html_writer::tag("tbody", $body);
$attributes = ["class" => "dtaTableData"]; $table = html_writer::tag("table", $header . $body, ["class" => "dtaTable"]);
$tmp .= html_writer::tag(
"td",
get_string("total_items", self::COMPONENT_NAME),
$attributes);
$tmp .= html_writer::tag( $html .= $table;
"td",
$summary->resultCount(),
$attributes);
$resultrowattributes = $tablerowattributes; // **Abstand zwischen Tabellen**
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $unknownattributes; $html .= html_writer::empty_tag("div", ["class" => "dtaSpacer"]);
$body .= html_writer::tag("tr", $tmp, $resultrowattributes); // **Kompetenzbewertungstabelle erstellen**
$body = "";
$tmp = "";
$tmp .= html_writer::tag("th", get_string("competencies", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]);
$tmp .= html_writer::empty_tag("th", ["class" => "dtaTableHeader"]);
$header = html_writer::tag("tr", $tmp, $tableheaderrowattributes);
$header = html_writer::tag("thead", $header);
$tmp = ""; $showncompetencies = explode(";", $summary->successfultestcompetencies);
$tmp .= html_writer::tag("td", get_string("tests_successful", self::COMPONENT_NAME), $attributes); $overallcompetencies = explode(";", $summary->overalltestcompetencies);
$tmp .= html_writer::tag( "td", $summary->successfulCount(), $attributes);
$resultrowattributes = $tablerowattributes; for ($index = 0, $size = count($overallcompetencies); $index < $size; $index++) {
$successrate = "?"; $comp = $overallcompetencies[$index];
$shown = $showncompetencies[$index];
// Kompetenz wird nur hinzugefügt, wenn sie bewertet wurde
if ($comp != "0") {
$resultrowattributes = $tablerowattributes;
$tmp = "";
$tmp .= html_writer::tag("td", get_string("comp" . $index, self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::tag("td", 100 * floatval($shown) / floatval($comp) . "% " .
"(" . $shown . " / " . $comp . ")", $attributes);
$tmp .= html_writer::tag("td", get_string("comp_expl" . $index, self::COMPONENT_NAME), $attributes);
if ($summary->unknownCount() > 0 || $summary->compilationErrorCount() > 0) { $body .= html_writer::tag("tr", $tmp, $resultrowattributes);
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $unknownattributes;
} else {
$successrate = round(($summary->successfulCount() / $summary->resultCount()) * 100, 2 );
if ($successrate < 50) {
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $compilationerrorattributes;
} else if ($successrate < 75) {
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $failureattributes;
} else {
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $successattributes;
}
} }
$body .= html_writer::tag("tr", $tmp, $resultrowattributes); }
$body = html_writer::tag("tbody", $body);
$tmp = ""; $html .= html_writer::tag("table", $header . $body, ["class" => "dtaTable"]);
$tmp .= html_writer::tag("td", get_string("failures", self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::tag("td", $summary->failedCount(), $attributes); // **Abstand zwischen Tabellen**
$html .= html_writer::empty_tag("div", ["class" => "dtaSpacer"]);
$resultrowattributes = $tablerowattributes;
if ($summary->failedCount() > 0) { // **Detailtabelle erstellen**
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $failureattributes; $tmp = "";
} else { $tmp .= html_writer::tag("th", get_string("details", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]);
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $successattributes; $tmp .= html_writer::empty_tag("th", ["class" => "dtaTableHeader"]);
$header = html_writer::tag("tr", $tmp, $tableheaderrowattributes);
$header = html_writer::tag("thead", $header);
$body = "";
$spacerrow = null;
foreach ($summary->results as $r) {
// Abstand zwischen den Ergebnissen
if (!is_null($spacerrow)) {
$body .= $spacerrow;
} }
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
$tmp = "";
$tmp .= html_writer::tag("td", get_string("compilation_errors", self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::tag("td", $summary->compilationErrorCount(), $attributes);
$resultrowattributes = $tablerowattributes; $resultrowattributes = $tablerowattributes;
if ($summary->compilationErrorCount() > 0) {
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $compilationerrorattributes;
} else {
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $successattributes;
}
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
$tmp = "";
$tmp .= html_writer::tag("td", get_string("unknown_state", self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::tag("td", $summary->unknownCount(), $attributes);
$resultrowattributes = $tablerowattributes; // CSS-Klasse basierend auf dem Status des Ergebnisses hinzufügen
if ($summary->unknownCount() > 0) { if ($r->state == 0) {
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $unknownattributes; $resultrowattributes['class'] .= ' dtaResultUnknown';
} else { } else if ($r->state == 1) {
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $successattributes; $resultrowattributes['class'] .= ' dtaResultSuccess';
} else if ($r->state == 2) {
$resultrowattributes['class'] .= ' dtaResultFailure';
} else if ($r->state == 3) {
$resultrowattributes['class'] .= ' dtaResultCompilationError';
} }
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
$tmp = ""; $tmp = "";
$tmp .= html_writer::tag("td", html_writer::tag("b", get_string("success_rate", self::COMPONENT_NAME)), $attributes); $tmp .= html_writer::tag("td", get_string("package_name", self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::tag( $tmp .= html_writer::tag("td", $r->packagename, $attributes);
"td", $tmp .= html_writer::tag("td", get_string("unit_name", self::COMPONENT_NAME), $attributes);
html_writer::tag("b", $summary->successfulCount() $tmp .= html_writer::tag("td", $r->classname, $attributes);
. "/" . (($summary->compilationErrorCount() == 0 && $summary->unknownCount() == 0) ? $summary->resultCount() $tmp .= html_writer::tag("td", get_string("test_name", self::COMPONENT_NAME), $attributes);
. " (" . $successrate . "%)" $tmp .= html_writer::tag("td", $r->name, $attributes);
: "?")),
$attributes);
$resultrowattributes = $tablerowattributes;
if ($summary->unknownCount() > 0 || $summary->compilationErrorCount() > 0) {
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $unknownattributes;
} else {
if ($successrate < 50) {
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $compilationerrorattributes;
} else if ($successrate < 75) {
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $failureattributes;
} else {
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $successattributes;
}
}
$body .= html_writer::tag("tr", $tmp, $resultrowattributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes);
$body = html_writer::tag("tbody", $body);
$table = html_writer::tag("table", $header . $body, ["class" => "dtaTable"]);
$html .= $table;
// Add empty div for spacing between summary and compentency table.
$html .= html_writer::empty_tag("div", ["class" => "dtaSpacer"]);
// Competency assessment table.
$body = "";
$tmp = ""; $tmp = "";
$tmp .= html_writer::tag("th", get_string("competencies", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]); $tmp .= html_writer::tag("td", get_string("status", self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::empty_tag("th", ["class" => "dtaTableHeader"]); $tmp .= html_writer::tag("td", DtaResult::getStateName($r->state), $attributes);
$header = html_writer::tag("tr", $tmp, $tableheaderrowattributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes);
$header = html_writer::tag("thead", $header);
$showncompetencies = explode(";", $summary->successfultestcompetencies);
$overallcompetencies = explode(";", $summary->overalltestcompetencies);
for ($index = 0, $size = count($overallcompetencies); $index < $size; $index++) {
$comp = $overallcompetencies[$index];
$shown = $showncompetencies[$index];
// If the competency was actually assessed by the assignment and tests, add a row in the table.
if ($comp != "0") {
// New copy of base attributes array.
$resultrowattributes = $tablerowattributes;
$tmp = "";
$tmp .= html_writer::tag("td", get_string("comp" . $index, self::COMPONENT_NAME), $resultrowattributes);
$tmp .= html_writer::tag("td", 100 * floatval($shown) / floatval($comp) . "% " .
"(" . $shown . " / " . $comp . ")", $resultrowattributes);
$tmp .= html_writer::tag("td", get_string("comp_expl" . $index, self::COMPONENT_NAME), $resultrowattributes);
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
}
}
$body = html_writer::tag("tbody", $body);
$html .= html_writer::tag("table", $header . $body, ["class" => "dtaTable"]);
// Add empty div for spacing between competency and details table.
$html .= html_writer::empty_tag("div", ["class" => "dtaSpacer"]);
// Details table.
$tmp = "";
$tmp .= html_writer::tag("th", get_string("details", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]);
$tmp .= html_writer::empty_tag("th", ["class" => "dtaTableHeader"]);
$header = html_writer::tag("tr", $tmp, $tableheaderrowattributes);
$header = html_writer::tag("thead", $header);
$body = "";
$spacerrow = null;
foreach ($summary->results as $r) {
// Add spacer first if not null.
if (!is_null($spacerrow)) {
$body .= $spacerrow;
}
// New copy of base attributes array.
$resultrowattributes = $tablerowattributes;
// Check which css class to add for the colored left-border according to resuls state.
if ($r->state == 0) {
$resultrowattributes['class'] = $resultrowattributes['class'] . ' dtaResultUnknown';
} else if ($r->state == 1) {
$resultrowattributes['class'] = $resultrowattributes['class'] . ' dtaResultSuccess';
} else if ($r->state == 2) {
$resultrowattributes['class'] = $resultrowattributes['class'] . ' dtaResultFailure';
} else if ($r->state == 3) {
$resultrowattributes['class'] = $resultrowattributes['class'] . ' dtaResultCompilationError';
}
// Zusätzliche Informationen für nicht erfolgreiche Zustände
if ($r->state != 1) {
$tmp = ""; $tmp = "";
$tmp .= html_writer::tag( $tmp .= html_writer::tag("td", get_string("failure_type", self::COMPONENT_NAME), $attributes);
"td", $tmp .= html_writer::tag("td", $r->failureType, $attributes);
get_string("package_name", self::COMPONENT_NAME),
$attributes);
$tmp .= html_writer::tag(
"td",
$r->packagename,
$attributes);
$tmp .= html_writer::tag(
"td",
get_string("unit_name", self::COMPONENT_NAME),
$attributes);
$tmp .= html_writer::tag(
"td",
$r->classname,
$attributes);
$tmp .= html_writer::tag(
"td",
get_string("test_name", self::COMPONENT_NAME),
$attributes);
$tmp .= html_writer::tag(
"td",
$r->name,
$attributes);
$body .= html_writer::tag("tr", $tmp, $resultrowattributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes);
$tmp = ""; $tmp = "";
$tmp .= html_writer::tag( $tmp .= html_writer::tag("td", get_string("failure_reason", self::COMPONENT_NAME), $attributes);
"td", $tmp .= html_writer::tag("td", $r->failureReason, $attributes);
get_string("status", self::COMPONENT_NAME),
$attributes);
$tmp .= html_writer::tag(
"td",
DtaResult::getStateName($r->state),
$attributes);
$body .= html_writer::tag("tr", $tmp, $resultrowattributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes);
// If state is something different than successful, show additional rows. // Zeilennummer anzeigen, falls vorhanden
if ($r->state != 1) { if (!is_null($r->lineNumber) && $r->lineNumber > 0) {
$tmp = ""; $tmp = "";
$tmp .= html_writer::tag( $tmp .= html_writer::tag("td", get_string("line_no", self::COMPONENT_NAME), $attributes);
"td", $tmp .= html_writer::tag("td", $r->lineNumber, $attributes);
get_string("failure_type", self::COMPONENT_NAME),
$attributes);
$tmp .= html_writer::tag(
"td",
$r->failureType,
$attributes);
$body .= html_writer::tag("tr", $tmp, $resultrowattributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes);
}
// Spaltennummer anzeigen, falls vorhanden
if (!is_null($r->columnNumber) && $r->columnNumber > 0) {
$tmp = ""; $tmp = "";
$tmp .= html_writer::tag( $tmp .= html_writer::tag("td", get_string("col_no", self::COMPONENT_NAME), $attributes);
"td", $tmp .= html_writer::tag("td", $r->columnNumber, $attributes);
get_string("failure_reason", self::COMPONENT_NAME),
$attributes);
$tmp .= html_writer::tag(
"td",
$r->failureReason,
$attributes);
$body .= html_writer::tag("tr", $tmp, $resultrowattributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes);
}
// Only show line, column and position if they have useful values. // Position anzeigen, falls vorhanden
if (!is_null($r->lineNumber) && $r->lineNumber > 0) { if (!is_null($r->position) && $r->position > 0) {
$tmp = "";
$tmp .= html_writer::tag(
"td",
get_string("line_no", self::COMPONENT_NAME),
$attributes);
$tmp .= html_writer::tag(
"td",
$r->lineNumber,
$attributes);
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
}
if (!is_null($r->columnNumber) && $r->columnNumber > 0) {
$tmp = "";
$tmp .= html_writer::tag(
"td",
get_string("col_no", self::COMPONENT_NAME),
$attributes);
$tmp .= html_writer::tag(
"td",
$r->columnNumber,
$attributes);
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
}
if (!is_null($r->position) && $r->position > 0) {
$tmp = "";
$tmp .= html_writer::tag(
"td",
get_string("pos", self::COMPONENT_NAME),
$attributes);
$tmp .= html_writer::tag(
"td",
$r->position,
$attributes);
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
}
$tmp = ""; $tmp = "";
$tmp .= html_writer::tag( $tmp .= html_writer::tag("td", get_string("pos", self::COMPONENT_NAME), $attributes);
"td", $tmp .= html_writer::tag("td", $r->position, $attributes);
get_string("stacktrace", self::COMPONENT_NAME),
$attributes);
$tmp .= html_writer::tag(
"td",
html_writer::tag("details", $r->stacktrace, ["class" => "dtaStacktraceDetails"]),
$attributes);
$body .= html_writer::tag("tr", $tmp, $resultrowattributes); $body .= html_writer::tag("tr", $tmp, $resultrowattributes);
} }
// Set spacerrow value if null for next round separation. // Stacktrace anzeigen
if (is_null($spacerrow)) { $tmp = "";
$spacerrow = html_writer::empty_tag("tr", ["class" => "dtaTableSpacer"]); $tmp .= html_writer::tag("td", get_string("stacktrace", self::COMPONENT_NAME), $attributes);
} $tmp .= html_writer::tag("td", html_writer::tag("details", $r->stacktrace, ["class" => "dtaStacktraceDetails"]), $attributes);
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
} }
$html .= html_writer::tag("table", $header . $body, ["class" => "dtaTable"]);
// Wrap generated html into final div. // Spacerrow für den nächsten Durchlauf setzen
$html = html_writer::div($html, "dtaSubmissionDetails"); if (is_null($spacerrow)) {
$spacerrow = html_writer::empty_tag("tr", ["class" => "dtaTableSpacer"]);
}
}
$body = html_writer::tag("tbody", $body);
$html .= html_writer::tag("table", $header . $body, ["class" => "dtaTable"]);
// **Abstand zwischen Detailtabelle und Empfehlungstabelle**
$html .= html_writer::empty_tag("div", ["class" => "dtaSpacer"]);
// **Empfehlungstabelle hinzufügen**
// Empfehlungen für die Submission abrufen
$recommendations = DbUtils::get_recommendations_from_database($assignmentid, $submissionid);
if (!empty($recommendations)) {
// Überschrift für Empfehlungen
$html .= html_writer::tag('h3', get_string('recommendations', self::COMPONENT_NAME));
// Tabellenkopf für Empfehlungen
$tableheader = "";
$tableheader .= html_writer::tag("th", get_string("topic", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]);
$tableheader .= html_writer::tag("th", get_string("exercise_name", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]);
$tableheader .= html_writer::tag("th", get_string("url", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]);
$tableheader .= html_writer::tag("th", get_string("difficulty", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]);
$tableheader .= html_writer::tag("th", get_string("score", self::COMPONENT_NAME), ["class" => "dtaTableHeader"]);
$tableheader = html_writer::tag("tr", $tableheader, ["class" => "dtaTableHeaderRow"]);
$tableheader = html_writer::tag("thead", $tableheader);
// Tabellenkörper für Empfehlungen
$tablebody = "";
foreach ($recommendations as $recommendation) {
$tablerow = "";
$tablerow .= html_writer::tag("td", $recommendation->topic, $attributes);
$tablerow .= html_writer::tag("td", $recommendation->exercise_name, $attributes);
$tablerow .= html_writer::tag("td", html_writer::link($recommendation->url, $recommendation->url), $attributes);
$tablerow .= html_writer::tag("td", $recommendation->difficulty, $attributes);
$tablerow .= html_writer::tag("td", $recommendation->score, $attributes);
$tablebody .= html_writer::tag("tr", $tablerow, $tablerowattributes);
}
$tablebody = html_writer::tag("tbody", $tablebody);
return $html; // Empfehlungstabelle zusammenstellen
$html .= html_writer::tag("table", $tableheader . $tablebody, ["class" => "dtaTable"]);
} }
// Abschließendes Div für die gesamte HTML-Ausgabe
$html = html_writer::div($html, "dtaSubmissionDetails");
return $html;
}
} }
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
<FIELD NAME="submission_id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/> <FIELD NAME="submission_id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="successful_competencies" TYPE="char" LENGTH="80" NOTNULL="false"/> <FIELD NAME="successful_competencies" TYPE="char" LENGTH="80" NOTNULL="false"/>
<FIELD NAME="tested_competencies" TYPE="char" LENGTH="80" NOTNULL="false"/> <FIELD NAME="tested_competencies" TYPE="char" LENGTH="80" NOTNULL="false"/>
<FIELD NAME="recommendations" TYPE="char" LENGTH="160" NOTNULL="false"/>
<FIELD NAME="timestamp" TYPE="int" LENGTH="10"/> <FIELD NAME="timestamp" TYPE="int" LENGTH="10"/>
<FIELD NAME="global_stacktrace" TYPE="text"/> <FIELD NAME="global_stacktrace" TYPE="text"/>
</FIELDS> </FIELDS>
...@@ -21,6 +20,23 @@ ...@@ -21,6 +20,23 @@
<KEY NAME="fk_submission" TYPE="foreign" FIELDS="submission_id" REFTABLE="assign_submission" REFFIELDS="id" COMMENT="The submission this summary relates to."/> <KEY NAME="fk_submission" TYPE="foreign" FIELDS="submission_id" REFTABLE="assign_submission" REFFIELDS="id" COMMENT="The submission this summary relates to."/>
</KEYS> </KEYS>
</TABLE> </TABLE>
<TABLE NAME="assignsubmission_dta_recommendations" COMMENT="Stores recommendation data">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" COMMENT="Primary Key" />
<FIELD NAME="assignment_id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="submission_id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="topic" TYPE="char" LENGTH="255" NOTNULL="true" COMMENT="Recommendation Topic" />
<FIELD NAME="exercise_name" TYPE="char" LENGTH="255" NOTNULL="true" COMMENT="Exercise Name" />
<FIELD NAME="url" TYPE="char" LENGTH="255" NOTNULL="true" COMMENT="Exercise URL" />
<FIELD NAME="difficulty" TYPE="number" LENGTH="10" NOTNULL="true" COMMENT="Exercise Difficulty" />
<FIELD NAME="score" TYPE="number" LENGTH="10" NOTNULL="true" COMMENT="Exercise Score" />
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="fk_assignment" TYPE="foreign" FIELDS="assignment_id" REFTABLE="assign" REFFIELDS="id" COMMENT="The assignment instance this recommendations relates to"/>
<KEY NAME="fk_submission" TYPE="foreign" FIELDS="submission_id" REFTABLE="assign_submission" REFFIELDS="id" COMMENT="The submission this recommendations relates to."/>
</KEYS>
</TABLE>
<TABLE NAME="assignsubmission_dta_result" COMMENT="DTA testrun single test results"> <TABLE NAME="assignsubmission_dta_result" COMMENT="DTA testrun single test results">
<FIELDS> <FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/> <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
......
...@@ -151,7 +151,6 @@ $string["privacy:metadata:assignsubmission_dta_summary:timestamp"] = "Date and t ...@@ -151,7 +151,6 @@ $string["privacy:metadata:assignsubmission_dta_summary:timestamp"] = "Date and t
$string["privacy:metadata:assignsubmission_dta_summary"] = "Stack trace of the compilation and test if major problems occur"; $string["privacy:metadata:assignsubmission_dta_summary"] = "Stack trace of the compilation and test if major problems occur";
$string["privacy:metadata:assignsubmission_dta_summary:successful_competencies"] = "List of the successfully tested competencies"; $string["privacy:metadata:assignsubmission_dta_summary:successful_competencies"] = "List of the successfully tested competencies";
$string["privacy:metadata:assignsubmission_dta_summary:tested_competencies"] = "List of the tested competencies"; $string["privacy:metadata:assignsubmission_dta_summary:tested_competencies"] = "List of the tested competencies";
$string["privacy:metadata:assignsubmission_dta_summary:recommendations"] = "List of recommendations after submitting the code";
$string["privacy:metadata:assignsubmission_dta_summary"] = "Summary of Dockerized Test Agent (DTA) results"; $string["privacy:metadata:assignsubmission_dta_summary"] = "Summary of Dockerized Test Agent (DTA) results";
$string["privacy:metadata:assignsubmission_dta_result:package_name"] = "Package name of individual test"; $string["privacy:metadata:assignsubmission_dta_result:package_name"] = "Package name of individual test";
$string["privacy:metadata:assignsubmission_dta_result:class_name"] = "Class name of individual test"; $string["privacy:metadata:assignsubmission_dta_result:class_name"] = "Class name of individual test";
...@@ -165,3 +164,12 @@ $string["privacy:metadata:assignsubmission_dta_result:line_number"] = "Line numb ...@@ -165,3 +164,12 @@ $string["privacy:metadata:assignsubmission_dta_result:line_number"] = "Line numb
$string["privacy:metadata:assignsubmission_dta_result:position"] = "Position of failed individual compilation or test"; $string["privacy:metadata:assignsubmission_dta_result:position"] = "Position of failed individual compilation or test";
$string["privacy:metadata:assignsubmission_dta_result"] = "Individual Dockerized Test Agent (DTA) results"; $string["privacy:metadata:assignsubmission_dta_result"] = "Individual Dockerized Test Agent (DTA) results";
$string["privacy:metadata:dta_backend"] = "Dockerized Test Agent (DTA) backend ReST web service"; $string["privacy:metadata:dta_backend"] = "Dockerized Test Agent (DTA) backend ReST web service";
//PLUGIN
$string['recommendations'] = 'Recommendations';
$string['topic'] = 'Topic';
$string['exercise_name'] = 'Exercise Name';
$string['url'] = 'URL';
$string['difficulty'] = 'Difficulty';
$string['score'] = 'Score';
...@@ -240,66 +240,82 @@ class assign_submission_dta extends assign_submission_plugin { ...@@ -240,66 +240,82 @@ class assign_submission_dta extends assign_submission_plugin {
return count($files); return count($files);
} }
/** /**
* Save data to the database * Save data to the database
* *
* @param stdClass $submission * @param stdClass $submission
* @param stdClass $data * @param stdClass $data
* @return bool * @return bool
*/ */
public function save(stdClass $submission, stdClass $data) { public function save(stdClass $submission, stdClass $data) {
$data = file_postupdate_standard_filemanager( $data = file_postupdate_standard_filemanager(
$data, $data,
'tasks', 'tasks',
$this->get_file_options(false), $this->get_file_options(false),
$this->assignment->get_context(), $this->assignment->get_context(),
self::COMPONENT_NAME, self::COMPONENT_NAME,
self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION, self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION,
$submission->id $submission->id
); );
// If submission is empty leave directly.
if ($this->is_empty($submission)) {
return true;
}
// If submission is empty leave directly. // Get submitted files.
if ($this->is_empty($submission)) { $fs = get_file_storage();
return true; $files = $fs->get_area_files(
} // Id of current assignment.
$this->assignment->get_context()->id,
self::COMPONENT_NAME,
self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION,
$submission->id,
'id',
false
);
// Check if a file is uploaded.
if (empty($files)) {
\core\notification::error(get_string("no_submissionfile_warning", self::COMPONENT_NAME));
return true;
}
// Get submitted files. // Get the file.
$fs = get_file_storage(); $file = reset($files);
$files = $fs->get_area_files(
// Id of current assignment.
$this->assignment->get_context()->id,
self::COMPONENT_NAME,
self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION,
$submission->id,
'id',
false
);
// Check if a file is uploaded. // Send file to backend.
if (empty($files)) { $response = DtaBackendUtils::send_submission_to_backend($this->assignment, $submission->id, $file);
\core\notification::error(get_string("no_submissionfile_warning", self::COMPONENT_NAME));
return true;
}
// Get the file. // With a null response, return an error.
$file = reset($files); if (is_null($response)) {
return false;
}
// Send file to backend. // Convert received json to valid class instances.
$response = DtaBackendUtils::send_submission_to_backend($this->assignment, $submission->id, $file); $resultsummary = DtaResultSummary::decodejson($response);
// Log an error message.
$recommendations = DtaResultSummary::decodeJsonRecommendation($response);
// With a null response, return an error. error_log(print_r($recommendations,true));
if (is_null($response)) {
return false;
}
// Convert received json to valid class instances.
$resultsummary = DtaResultSummary::decodejson($response);
// Persist new results to database.
DbUtils::storeresultsummarytodatabase($this->assignment->get_instance()->id, $submission->id, $resultsummary);
return true; // Persist new results to database.
} DbUtils::storeresultsummarytodatabase($this->assignment->get_instance()->id, $submission->id, $resultsummary);
// Store the array of records in the database.
DbUtils::storeRecommendationstoDatabase($this->assignment->get_instance()->id, $submission->id, $recommendations);
return true;
}
/** /**
* Display a short summary of the test results of the submission * Display a short summary of the test results of the submission
......
...@@ -147,6 +147,7 @@ class DtaResultSummary { ...@@ -147,6 +147,7 @@ class DtaResultSummary {
*/ */
public static function decodejson(string $jsonstring): DtaResultSummary { public static function decodejson(string $jsonstring): DtaResultSummary {
$response = json_decode($jsonstring); $response = json_decode($jsonstring);
$summary = new DtaResultSummary(); $summary = new DtaResultSummary();
$summary->timestamp = $response->timestamp; $summary->timestamp = $response->timestamp;
...@@ -160,6 +161,35 @@ class DtaResultSummary { ...@@ -160,6 +161,35 @@ class DtaResultSummary {
return $summary; return $summary;
} }
public static function decodeJsonRecommendation(string $jsonstring): array {
// Decode the JSON string into a PHP object
$response = json_decode($jsonstring);
error_log("decodeJsonRecommendation");
error_log(print_r($response, true));
// Initialize an empty array to store recommendations
$recommendations = [];
// Loop through the recommendations in the response
if (!empty($response->recommendations)) {
foreach ($response->recommendations as $recommendation) {
// For each recommendation, create an associative array with the properties
$recommendations[] = [
'topic' => $recommendation->topic ?? null,
'url' => $recommendation->exerciseName ?? null,
'exercise_name' => $recommendation->url ?? null,
'difficulty' => $recommendation->difficulty ?? null,
'score' => $recommendation->score ?? null
];
}
}
error_log(print_r($recommendations,true));
// Return the array of recommendations
return $recommendations;
}
/** /**
* Decodes the array of JSON detail results returned by the backend service call into the plugin PHP data structure. * Decodes the array of JSON detail results returned by the backend service call into the plugin PHP data structure.
* @param array $jsonarray decoded json array of results array * @param array $jsonarray decoded json array of results array
......
dta1.0.zip 0 → 100644
File added
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment