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 {
*/
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
*
......@@ -83,6 +103,52 @@ class DbUtils {
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
......@@ -107,8 +173,7 @@ class DbUtils {
$summaryrecord->global_stacktrace = $summary->globalstacktrace;
$summaryrecord->successful_competencies = $summary->successfultestcompetencies;
$summaryrecord->tested_competencies = $summary->overalltestcompetencies;
$summaryrecord->recommendations = $summary->recommendations;
// Prepare results to persist to array.
$resultrecords = [];
foreach ($summary->results as $r) {
......@@ -161,6 +226,8 @@ class DbUtils {
$DB->delete_records(self::TABLE_RESULT, 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,
'global_stacktrace' => 'privacy:metadata:assignsubmission_dta_summary:global_stacktrace',
'successful_competencies' => 'privacy:metadata:assignsubmission_dta_summary:successful_competencies',
'tested_competencies' => 'privacy:metadata:assignsubmission_dta_summary:tested_competencies',
'recommendations' => 'privacy:metadata:assignsubmission_dta_summary:recommendations',
],
'privacy:metadata:assignsubmission_dta_summary'
......
......@@ -19,7 +19,6 @@
*
* @package assignsubmission_dta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @copyright Gero Lueckemeyer and student project teams
*/
class view_submission_utils {
......@@ -85,342 +84,318 @@ class view_submission_utils {
}
/**
* generates detailed view html
*
* @param int $assignmentid assignment
* @param int $submissionid submission to create a report for
*/
public static function generatedetailhtml(
int $assignmentid,
int $submissionid
): string {
// Fetch data.
$summary = DbUtils::getResultSummaryFromDatabase($assignmentid, $submissionid);
$html = "";
// Define a few css classes and prepare html attribute arrays to beautify the output.
$tableheaderrowattributes = ["class" => "dtaTableHeaderRow"];
$tablerowattributes = ["class" => "dtaTableRow"];
$resultrowattributes = $tablerowattributes;
$unknownattributes = 'dtaResultUnknown';
$successattributes = 'dtaResultSuccess';
$failureattributes = 'dtaResultFailure';
$compilationerrorattributes = 'dtaResultCompilationError';
// Summary table.
$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);
* Generiert die detaillierte HTML-Ansicht, einschließlich Zusammenfassung, Kompetenzen, Details und Empfehlungen.
*
* @param int $assignmentid Assignment-ID
* @param int $submissionid Submission-ID, für die der Bericht erstellt wird
* @return string HTML-Code
*/
public static function generatedetailhtml(
int $assignmentid,
int $submissionid
): string {
// HTML-Inhalt initialisieren
$html = "";
// Daten abrufen
$summary = DbUtils::getResultSummaryFromDatabase($assignmentid, $submissionid);
// CSS-Klassen und HTML-Attributarrays definieren
$tableheaderrowattributes = ["class" => "dtaTableHeaderRow"];
$tablerowattributes = ["class" => "dtaTableRow"];
$attributes = ["class" => "dtaTableData"];
$unknownattributes = 'dtaResultUnknown';
$successattributes = 'dtaResultSuccess';
$failureattributes = 'dtaResultFailure';
$compilationerrorattributes = 'dtaResultCompilationError';
// **Zusammenfassungstabelle erstellen**
// Kopfzeile
$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 = "";
$tmp = "";
$attributes = ["class" => "dtaTableData"];
$tmp .= html_writer::tag(
"td",
get_string("total_items", self::COMPONENT_NAME),
$attributes);
// Tabelle zusammenstellen
$body = html_writer::tag("tbody", $body);
$table = html_writer::tag("table", $header . $body, ["class" => "dtaTable"]);
$tmp .= html_writer::tag(
"td",
$summary->resultCount(),
$attributes);
$html .= $table;
$resultrowattributes = $tablerowattributes;
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $unknownattributes;
// **Abstand zwischen Tabellen**
$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 = "";
$tmp .= html_writer::tag("td", get_string("tests_successful", self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::tag( "td", $summary->successfulCount(), $attributes);
$showncompetencies = explode(";", $summary->successfultestcompetencies);
$overallcompetencies = explode(";", $summary->overalltestcompetencies);
$resultrowattributes = $tablerowattributes;
$successrate = "?";
for ($index = 0, $size = count($overallcompetencies); $index < $size; $index++) {
$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) {
$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("tr", $tmp, $resultrowattributes);
$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'] = $resultrowattributes['class'] . " " . $failureattributes;
} else {
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $successattributes;
}
$body = html_writer::tag("tbody", $body);
$html .= html_writer::tag("table", $header . $body, ["class" => "dtaTable"]);
// **Abstand zwischen Tabellen**
$html .= html_writer::empty_tag("div", ["class" => "dtaSpacer"]);
// **Detailtabelle erstellen**
$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) {
// 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;
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;
if ($summary->unknownCount() > 0) {
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $unknownattributes;
} else {
$resultrowattributes['class'] = $resultrowattributes['class'] . " " . $successattributes;
// CSS-Klasse basierend auf dem Status des Ergebnisses hinzufügen
if ($r->state == 0) {
$resultrowattributes['class'] .= ' dtaResultUnknown';
} else if ($r->state == 1) {
$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 .= 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'] = $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;
}
}
$tmp .= html_writer::tag("td", 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("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 .= 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);
$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';
}
$tmp .= html_writer::tag("td", get_string("status", self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::tag("td", DtaResult::getStateName($r->state), $attributes);
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
// Zusätzliche Informationen für nicht erfolgreiche Zustände
if ($r->state != 1) {
$tmp = "";
$tmp .= html_writer::tag(
"td",
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);
$tmp .= html_writer::tag("td", get_string("failure_type", self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::tag("td", $r->failureType, $attributes);
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
$tmp = "";
$tmp .= html_writer::tag(
"td",
get_string("status", self::COMPONENT_NAME),
$attributes);
$tmp .= html_writer::tag(
"td",
DtaResult::getStateName($r->state),
$attributes);
$tmp .= html_writer::tag("td", get_string("failure_reason", self::COMPONENT_NAME), $attributes);
$tmp .= html_writer::tag("td", $r->failureReason, $attributes);
$body .= html_writer::tag("tr", $tmp, $resultrowattributes);
// If state is something different than successful, show additional rows.
if ($r->state != 1) {
// Zeilennummer anzeigen, falls vorhanden
if (!is_null($r->lineNumber) && $r->lineNumber > 0) {
$tmp = "";
$tmp .= html_writer::tag(
"td",
get_string("failure_type", self::COMPONENT_NAME),
$attributes);
$tmp .= html_writer::tag(
"td",
$r->failureType,
$attributes);
$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);
}
// Spaltennummer anzeigen, falls vorhanden
if (!is_null($r->columnNumber) && $r->columnNumber > 0) {
$tmp = "";
$tmp .= html_writer::tag(
"td",
get_string("failure_reason", self::COMPONENT_NAME),
$attributes);
$tmp .= html_writer::tag(
"td",
$r->failureReason,
$attributes);
$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);
}
// Only show line, column and position if they have useful values.
if (!is_null($r->lineNumber) && $r->lineNumber > 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);
}
// Position anzeigen, falls vorhanden
if (!is_null($r->position) && $r->position > 0) {
$tmp = "";
$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);
$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);
}
// Set spacerrow value if null for next round separation.
if (is_null($spacerrow)) {
$spacerrow = html_writer::empty_tag("tr", ["class" => "dtaTableSpacer"]);
}
// Stacktrace anzeigen
$tmp = "";
$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.
$html = html_writer::div($html, "dtaSubmissionDetails");
// Spacerrow für den nächsten Durchlauf setzen
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 @@
<FIELD NAME="submission_id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="successful_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="global_stacktrace" TYPE="text"/>
</FIELDS>
......@@ -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."/>
</KEYS>
</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">
<FIELDS>
<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
$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: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_result:package_name"] = "Package 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
$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: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 {
return count($files);
}
/**
* Save data to the database
*
* @param stdClass $submission
* @param stdClass $data
* @return bool
*/
public function save(stdClass $submission, stdClass $data) {
$data = file_postupdate_standard_filemanager(
$data,
'tasks',
$this->get_file_options(false),
$this->assignment->get_context(),
self::COMPONENT_NAME,
self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION,
$submission->id
);
/**
* Save data to the database
*
* @param stdClass $submission
* @param stdClass $data
* @return bool
*/
public function save(stdClass $submission, stdClass $data) {
$data = file_postupdate_standard_filemanager(
$data,
'tasks',
$this->get_file_options(false),
$this->assignment->get_context(),
self::COMPONENT_NAME,
self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION,
$submission->id
);
// If submission is empty leave directly.
if ($this->is_empty($submission)) {
return true;
}
// If submission is empty leave directly.
if ($this->is_empty($submission)) {
return true;
}
// Get submitted files.
$fs = get_file_storage();
$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.
$fs = get_file_storage();
$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
);
// Get the file.
$file = reset($files);
// Check if a file is uploaded.
if (empty($files)) {
\core\notification::error(get_string("no_submissionfile_warning", self::COMPONENT_NAME));
return true;
}
// Send file to backend.
$response = DtaBackendUtils::send_submission_to_backend($this->assignment, $submission->id, $file);
// Get the file.
$file = reset($files);
// With a null response, return an error.
if (is_null($response)) {
return false;
}
// Send file to backend.
$response = DtaBackendUtils::send_submission_to_backend($this->assignment, $submission->id, $file);
// Convert received json to valid class instances.
$resultsummary = DtaResultSummary::decodejson($response);
// Log an error message.
$recommendations = DtaResultSummary::decodeJsonRecommendation($response);
// With a null response, return an error.
if (is_null($response)) {
return false;
}
error_log(print_r($recommendations,true));
// 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
......
......@@ -147,6 +147,7 @@ class DtaResultSummary {
*/
public static function decodejson(string $jsonstring): DtaResultSummary {
$response = json_decode($jsonstring);
$summary = new DtaResultSummary();
$summary->timestamp = $response->timestamp;
......@@ -160,6 +161,35 @@ class DtaResultSummary {
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.
* @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