Commit 4e16f800 authored by Kurzenberger's avatar Kurzenberger
Browse files

refactored the code for the code checker plugin

parent 0e5e6553
1 merge request!1Coding style and recommendations
Pipeline #10747 passed with stage
Showing with 903 additions and 675 deletions
+903 -675
<?php
namespace assignsubmission_dta;
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
......@@ -15,92 +14,119 @@ namespace assignsubmission_dta;
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* persistence layer utility class
*
* @package assignsubmission_dta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @copyright Gero Lueckemeyer and student project teams
*/
namespace assignsubmission_dta;
use assignsubmission_dta\dta_backend_utils;
use assignsubmission_dta\dta_view_submission_utils;
use assignsubmission_dta\models\dta_result;
use assignsubmission_dta\models\dta_result_summary;
use assignsubmission_dta\models\dta_recommendation;
/**
* Class dta_db_utils
*
* Persistence layer utility class for storing and retrieving
* DTA plugin data (results, summaries, recommendations).
*
* @package assignsubmission_dta
* @copyright 2023 Gero Lueckemeyer
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class dta_db_utils {
/**
* Summary database table name.
*/
private const ASSIGNSUBMISSION_DTA_TABLE_SUMMARY = "assignsubmission_dta_summary";
private const ASSIGNSUBMISSION_DTA_TABLE_SUMMARY = 'assignsubmission_dta_summary';
/**
* Result database table name.
*/
private const ASSIGNSUBMISSION_DTA_TABLE_RESULT = "assignsubmission_dta_result";
private const ASSIGNSUBMISSION_DTA_TABLE_RESULT = 'assignsubmission_dta_result';
private const ASSIGNSUBMISSION_DTA_TABLE_RECOMMENDATIONS = "assignsubmission_dta_recommendations";
/**
* Recommendations database table name.
*/
private const ASSIGNSUBMISSION_DTA_TABLE_RECOMMENDATIONS = 'assignsubmission_dta_recommendations';
public static function assignsubmission_dta_get_recommendations_from_database(int $assignmentid, int $submissionid): array {
global $DB,$USER;
/**
* Returns an array of recommendations from the database.
*
* @param int $assignmentid The assignment ID.
* @param int $submissionid The submission ID.
* @return array An array of recommendation records.
*/
public static function assignsubmission_dta_get_recommendations_from_database(
int $assignmentid,
int $submissionid
): array {
global $DB, $USER;
$userid = $USER->id;
// Schritt 1: Alle Empfehlungen abrufen
$records = $DB->get_records(self::ASSIGNSUBMISSION_DTA_TABLE_RECOMMENDATIONS, [
'assignment_id' => $assignmentid,
'submission_id' => $submissionid,
]);
// Schritt 2: Modul-ID für 'assign' abrufen
// Step 1: Retrieve all recommendations.
$records = $DB->get_records(
self::ASSIGNSUBMISSION_DTA_TABLE_RECOMMENDATIONS,
[
'assignment_id' => $assignmentid,
'submission_id' => $submissionid,
]
);
// Step 2: Retrieve module ID for 'assign'.
$module = $DB->get_record('modules', ['name' => 'assign'], 'id');
if (!$module) {
// Fehlerbehandlung, falls das Modul nicht gefunden wird
// Handle error case if the module is not found.
return $records;
}
$moduleid = $module->id;
print_r($records);
// Schritt 3: Überprüfe jeden Datensatz
// Step 3: Check each record.
foreach ($records as $key => $record) {
// Hol den Namen der Übung aus dem Datensatz
// Get the name of the exercise from the record.
$exercisename = $record->exercise_name;
// Suche das Assignment mit diesem Namen
// Find the assignment with this name.
$assign = $DB->get_record('assign', ['name' => $exercisename], 'id');
if ($assign) {
// Hole die Kursmodul-ID (coursemoduleid) für dieses Assignment
$cm = $DB->get_record('course_modules', [
'module' => $moduleid,
'instance' => $assign->id
], 'id');
// Get the course module ID for this assignment.
$cm = $DB->get_record(
'course_modules',
[
'module' => $moduleid,
'instance' => $assign->id,
],
'id'
);
if ($cm) {
// Überprüfe den Abschlussstatus für dieses Kursmodul und den Benutzer
$completion = $DB->get_record('course_modules_completion', [
'coursemoduleid' => $cm->id,
'userid' => $userid
], 'completionstate');
// Wenn der Abschlussstatus 1 ist, entferne den Datensatz aus $records
if ($completion && $completion->completionstate == 1) {
unset($records[$key]);
// Check the completion status for this course module and user.
$completion = $DB->get_record(
'course_modules_completion',
[
'coursemoduleid' => $cm->id,
'userid' => $userid,
],
'completionstate'
);
// If the completion state is 1, remove the record from $records.
if ($completion && (int)$completion->completionstate === 1) {
unset($records[$key]);
}
}
}
}
// Rückgabe der gefilterten Datensätze
// Return the filtered records.
return $records;
}
/**
* gets summary with all corresponding result entries
* Gets a summary with all corresponding result entries.
*
* @param int $assignmentid assignment id to search for
* @param int $submissionid submission id to search for
* @return DttResultSummary representing given submission
* @param int $assignmentid Assignment ID to search for.
* @param int $submissionid Submission ID to search for.
* @return dta_result_summary Summary representing the submission.
*/
public static function assignsubmission_dta_get_result_summary_from_database(
int $assignmentid,
......@@ -109,15 +135,21 @@ class dta_db_utils {
global $DB;
// Fetch data from database.
$summaryrecord = $DB->get_record(self::ASSIGNSUBMISSION_DTA_TABLE_SUMMARY, [
"assignment_id" => $assignmentid,
"submission_id" => $submissionid,
]);
$summaryrecord = $DB->get_record(
self::ASSIGNSUBMISSION_DTA_TABLE_SUMMARY,
[
'assignment_id' => $assignmentid,
'submission_id' => $submissionid,
]
);
$resultsarray = $DB->get_records(self::ASSIGNSUBMISSION_DTA_TABLE_RESULT, [
"assignment_id" => $assignmentid,
"submission_id" => $submissionid,
]);
$resultsarray = $DB->get_records(
self::ASSIGNSUBMISSION_DTA_TABLE_RESULT,
[
'assignment_id' => $assignmentid,
'submission_id' => $submissionid,
]
);
// Create a summary instance.
$summary = new dta_result_summary();
......@@ -146,55 +178,69 @@ class dta_db_utils {
return $summary;
}
/**
* Stores an array of recommendations in the database.
*
* @param int $assignmentid The assignment ID.
* @param int $submissionid The submission ID.
* @param array $recommendations An array of dta_recommendation objects.
*/
public static function assignsubmission_dta_store_recommendations_to_database(
int $assignmentid,
int $submissionid,
array $recommendations
): void {
global $DB;
error_log(print_r($recommendations, true));
// Debug output (you can remove or adapt this if unneeded).
debugging('Recommendations array: ' . json_encode($recommendations));
// If recommendations already exist, delete old values beforehand.
$existingrecords = $DB->get_records('assignsubmission_dta_recommendations', [
'assignment_id' => $assignmentid,
'submission_id' => $submissionid,
]);
if ($existingrecords) {
$DB->delete_records('assignsubmission_dta_recommendations', [
$existingrecords = $DB->get_records(
'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 ($recommendations as $recommendation) {
// Ensure $recommendation is an instance of DtaRecommendation
// Check if $recommendation is an instance of dta_recommendation.
if ($recommendation instanceof dta_recommendation) {
// Add assignment and submission IDs to the recommendation object
// Add assignment and submission IDs to the recommendation object.
$recommendation->assignment_id = $assignmentid;
$recommendation->submission_id = $submissionid;
error_log("Insert record");
error_log(print_r($recommendation, true));
// Insert the recommendation into the database
debugging('Inserting new recommendation record: ' . json_encode($recommendation));
// Insert the recommendation into the database.
$DB->insert_record('assignsubmission_dta_recommendations', $recommendation);
} else {
// Handle the case where $recommendation is not a DtaRecommendation instance
error_log("Invalid recommendation object");
// Handle the case where $recommendation is not a dta_recommendation instance.
debugging('Invalid recommendation object encountered.');
}
}
}
/**
* save given result summary and single results to database
* under given assignment and submission id
* Saves the given result summary and single results to the database
* under the specified assignment and submission ID.
*
* @param int $assignmentid assigment this is submission is linked to
* @param int $submissionid submission of this result
* @param dta_result_summary $summary instance to persist
* @param int $assignmentid Assignment this submission is linked to.
* @param int $submissionid Submission ID for these results.
* @param dta_result_summary $summary Summary instance to persist.
*/
public static function assignsubmission_dta_store_result_summary_to_database(
int $assignmentid,
......@@ -211,8 +257,8 @@ class dta_db_utils {
$summaryrecord->global_stacktrace = $summary->globalstacktrace;
$summaryrecord->successful_competencies = $summary->successfultestcompetencies;
$summaryrecord->tested_competencies = $summary->overalltestcompetencies;
// Prepare results to persist to array.
// Prepare results to persist.
$resultrecords = [];
foreach ($summary->results as $r) {
$record = new dta_result();
......@@ -232,21 +278,30 @@ class dta_db_utils {
}
// If results already exist, delete old values beforehand.
$submission = $DB->get_record(self::ASSIGNSUBMISSION_DTA_TABLE_SUMMARY, [
'assignment_id' => $assignmentid,
'submission_id' => $submissionid,
]);
if ($submission) {
$DB->delete_records(self::ASSIGNSUBMISSION_DTA_TABLE_RESULT, [
$submission = $DB->get_record(
self::ASSIGNSUBMISSION_DTA_TABLE_SUMMARY,
[
'assignment_id' => $assignmentid,
'submission_id' => $submissionid,
]);
]
);
$DB->delete_records(self::ASSIGNSUBMISSION_DTA_TABLE_SUMMARY, [
'assignment_id' => $assignmentid,
'submission_id' => $submissionid,
]);
if ($submission) {
$DB->delete_records(
self::ASSIGNSUBMISSION_DTA_TABLE_RESULT,
[
'assignment_id' => $assignmentid,
'submission_id' => $submissionid,
]
);
$DB->delete_records(
self::ASSIGNSUBMISSION_DTA_TABLE_SUMMARY,
[
'assignment_id' => $assignmentid,
'submission_id' => $submissionid,
]
);
}
// Create summary and single result entries.
......@@ -257,7 +312,7 @@ class dta_db_utils {
}
/**
* cleans up database if plugin is uninstalled
* Cleans up database if plugin is uninstalled.
*/
public static function assignsubmission_dta_uninstall_plugin_cleaup(): void {
global $DB;
......@@ -265,7 +320,5 @@ class dta_db_utils {
$DB->delete_records(self::ASSIGNSUBMISSION_DTA_TABLE_RESULT, null);
$DB->delete_records(self::ASSIGNSUBMISSION_DTA_TABLE_SUMMARY, null);
$DB->delete_records(self::ASSIGNSUBMISSION_DTA_TABLE_RECOMMENDATIONS, null);
}
}
<?php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - http://moodle.org/.
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
......@@ -16,40 +15,44 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains the backend webservice contact functionality for the DTA plugin
* This file contains the backend webservice contact functionality for the DTA plugin.
*
* @package assignsubmission_dta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @package assignsubmission_dta
* @copyright 2023 Your Name
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace assignsubmission_dta;
/**
* Backend webservice contact utility class
* Backend webservice contact utility class.
*
* @package assignsubmission_dta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @package assignsubmission_dta
* @copyright 2023 Your Name
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace assignsubmission_dta;
defined('MOODLE_INTERNAL') || die();
class dta_backend_utils {
/**
* Component name for the plugin.
*/
const ASSIGNSUBMISSION_DTA_COMPONENT_NAME = 'assignsubmission_dta';
public const ASSIGNSUBMISSION_DTA_COMPONENT_NAME = 'assignsubmission_dta';
/**
* Returns the base URL of the backend webservice as configured in the administration settings.
* @return string Backend host base URL
*
* @return string Backend host base URL.
*/
private static function assignsubmission_dta_get_backend_baseurl(): string {
$backendaddress = get_config(self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME, 'backendHost');
$backendaddress = get_config(
self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME,
'backendHost'
);
if (empty($backendaddress)) {
\core\notification::error(get_string('backendHost_not_set', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME));
\core\notification::error(
get_string('backendHost_not_set', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
);
}
return $backendaddress;
......@@ -58,9 +61,9 @@ class dta_backend_utils {
/**
* Sends the configuration text file uploaded by the teacher to the backend.
*
* @param \assign $assignment Assignment this test-config belongs to
* @param \stored_file $file Uploaded test-config
* @return bool True if no error occurred
* @param \assign $assignment Assignment this test-config belongs to.
* @param \stored_file $file Uploaded test-config.
* @return bool True if no error occurred.
*/
public static function assignsubmission_dta_send_testconfig_to_backend($assignment, $file): bool {
$backendaddress = self::assignsubmission_dta_get_backend_baseurl();
......@@ -88,12 +91,16 @@ class dta_backend_utils {
/**
* Sends submission config or archive to backend to be tested.
*
* @param \assign $assignment Assignment for the submission
* @param int $submissionid Submission ID of the current file
* @param \stored_file $file Submission config file or archive with submission
* @return string|null JSON string with test results or null on error
* @param \assign $assignment Assignment for the submission.
* @param int $submissionid Submission ID of the current file.
* @param \stored_file $file Submission config file or archive with submission.
* @return string|null JSON string with test results or null on error.
*/
public static function assignsubmission_dta_send_submission_to_backend($assignment, $submissionid, $file): ?string {
public static function assignsubmission_dta_send_submission_to_backend(
$assignment,
int $submissionid,
$file
): ?string {
$backendaddress = self::assignsubmission_dta_get_backend_baseurl();
if (empty($backendaddress)) {
return null;
......@@ -113,12 +120,12 @@ class dta_backend_utils {
/**
* Posts the given params to the given URL and returns the response as a string.
* @param string $url Full URL to request to
* @param array $params Parameters for HTTP request
*
* @return string|null Received body on success or null on error
* @param string $url Full URL to request.
* @param array $params Parameters for HTTP request.
* @return string|null Received body on success or null on error.
*/
private static function assignsubmission_dta_post($url, $params): ?string {
private static function assignsubmission_dta_post(string $url, array $params): ?string {
if (!isset($url) || !isset($params)) {
return null;
}
......@@ -128,23 +135,32 @@ class dta_backend_utils {
$curl = new \curl();
$response = $curl->post($url, $params, $options);
// Check state of request, if response code is a 2xx return the answer.
// Check state of request, if response code is 2xx, return the answer.
$info = $curl->get_info();
if ($info['http_code'] >= 200 && $info['http_code'] < 300) {
return $response;
}
// Something went wrong, return null and give an error message.
debugging(self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME . ': Post file to server was not successful: http_code=' . $info['http_code']);
// Something went wrong, return null and display an error message.
$msg = self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME
. ': Post file to server was not successful. HTTP code='
. $info['http_code'];
debugging($msg);
if ($info['http_code'] >= 400 && $info['http_code'] < 500) {
\core\notification::error(get_string('http_client_error_msg', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME));
\core\notification::error(
get_string('http_client_error_msg', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
);
return null;
} else if ($info['http_code'] >= 500 && $info['http_code'] < 600) {
\core\notification::error(get_string('http_server_error_msg', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME));
\core\notification::error(
get_string('http_server_error_msg', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
);
return null;
} else {
\core\notification::error(get_string('http_unknown_error_msg', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME) . $info['http_code'] . $response);
$unknownmsg = get_string('http_unknown_error_msg', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
. $info['http_code'] . ' ' . $response;
\core\notification::error($unknownmsg);
return null;
}
}
......
This diff is collapsed.
<?php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - http://moodle.org/.
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
......@@ -15,7 +15,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Entity class for DTA submission plugin recommendation
* Entity class for DTA submission plugin recommendation.
*
* @package assignsubmission_dta
* @copyright 2023 Gero Lueckemeyer
......@@ -24,10 +24,8 @@
namespace assignsubmission_dta\models;
defined('MOODLE_INTERNAL') || die();
/**
* Entity class for DTA submission plugin recommendation
* Entity class for DTA submission plugin recommendation.
*
* @package assignsubmission_dta
* @copyright 2023
......@@ -41,9 +39,9 @@ class dta_recommendation {
public $topic;
/**
* @var string $exercise_name Name of the exercise.
* @var string $exerciseName Name of the exercise.
*/
public $exercise_name;
public $exerciseName;
/**
* @var string $url URL of the exercise.
......@@ -61,22 +59,22 @@ class dta_recommendation {
public $score;
/**
* Decodes the JSON recommendations returned by the backend service call into an array of DtaRecommendation objects.
* Decodes the JSON recommendations returned by the backend service call into an array of dta_recommendation objects.
*
* @param string $jsonstring JSON string containing recommendations
* @return array Array of DtaRecommendation objects
* @param string $jsonstring JSON string containing recommendations.
* @return array Array of dta_recommendation objects.
*/
public static function assignsubmission_dta_decode_json_recommendations(string $jsonstring): array {
$response = json_decode($jsonstring);
$recommendations = [];
// Prüfe, ob Empfehlungen vorhanden sind
// Check if recommendations exist.
if (!empty($response->recommendations)) {
foreach ($response->recommendations as $recommendation) {
$rec = new dta_recommendation();
$rec->topic = $recommendation->topic ?? null;
$rec->exercise_name = $recommendation->url ?? null;
// Map correct fields to the renamed variable names:
$rec->exerciseName = $recommendation->url ?? null;
$rec->url = $recommendation->exerciseName ?? null;
$rec->difficulty = $recommendation->difficulty ?? null;
$rec->score = $recommendation->score ?? null;
......
<?php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - http://moodle.org/.
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
......@@ -15,7 +15,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Entity class for DTA submission plugin result
* Entity class for DTA submission plugin result.
*
* @package assignsubmission_dta
* @copyright 2023 Gero Lueckemeyer and student project teams
......@@ -24,10 +24,8 @@
namespace assignsubmission_dta\models;
defined('MOODLE_INTERNAL') || die();
/**
* Entity class for DTA submission plugin result
* Entity class for DTA submission plugin result.
*
* @package assignsubmission_dta
* @copyright 2023 Gero Lueckemeyer and student project teams
......@@ -38,7 +36,7 @@ class dta_result {
/**
* Broadly used in logic, parametrized for easier change.
*/
const ASSIGNSUBMISSION_DTA_COMPONENT_NAME = 'assignsubmission_dta';
public const ASSIGNSUBMISSION_DTA_COMPONENT_NAME = 'assignsubmission_dta';
/**
* @var string $packagename Package name of the test.
......@@ -97,15 +95,15 @@ class dta_result {
/**
* Returns the name of a state with the given number for display.
*
* @param int $state Number of the state
* @return string Name of state as defined
* @param int $state Number of the state.
* @return string Name of state as defined.
*/
public static function assignsubmission_dta_get_statename(int $state): string {
if ($state == 1) {
if ($state === 1) {
return get_string('tests_successful', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME);
} else if ($state == 2) {
} else if ($state === 2) {
return get_string('failures', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME);
} else if ($state == 3) {
} else if ($state === 3) {
return get_string('compilation_errors', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME);
} else {
return get_string('unknown_state', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME);
......
<?php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - http://moodle.org/.
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
......@@ -15,7 +15,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Entity class for DTA submission plugin result summary
* Entity class for DTA submission plugin result summary.
*
* @package assignsubmission_dta
* @copyright 2023 Gero Lueckemeyer and student project teams
......@@ -24,10 +24,8 @@
namespace assignsubmission_dta\models;
defined('MOODLE_INTERNAL') || die();
/**
* Entity class for DTA submission plugin result summary
* Entity class for DTA submission plugin result summary.
*
* @package assignsubmission_dta
* @copyright 2023 Gero Lueckemeyer and student project teams
......@@ -36,22 +34,22 @@ defined('MOODLE_INTERNAL') || die();
class dta_result_summary {
/**
* @var int $timestamp Result timestamp for chronological ordering and deletion of previous results.
* @var int $timestamp Timestamp for ordering and deletion of previous results.
*/
public $timestamp;
/**
* @var string $globalstacktrace Global stack trace if applicable, empty string otherwise.
* @var string $globalstacktrace Global stack trace if applicable, empty otherwise.
*/
public $globalstacktrace;
/**
* @var string $successfultestcompetencies Successfully tested competencies according to tests and weights, empty string otherwise.
* @var string $successfultestcompetencies Successfully tested competencies (tests and weights), or empty string.
*/
public $successfultestcompetencies;
/**
* @var string $overalltestcompetencies Overall tested competencies according to tests and weights, empty string otherwise.
* @var string $overalltestcompetencies Overall tested competencies (tests and weights), or empty string.
*/
public $overalltestcompetencies;
......@@ -63,8 +61,8 @@ class dta_result_summary {
/**
* Decodes the JSON result summary returned by the backend service call into the plugin PHP data structure.
*
* @param string $jsonstring JSON string containing DtaResultSummary
* @return DtaResultSummary The result summary
* @param string $jsonstring JSON string containing DtaResultSummary.
* @return dta_result_summary The result summary.
*/
public static function assignsubmission_dta_decode_json(string $jsonstring): dta_result_summary {
$response = json_decode($jsonstring);
......@@ -82,10 +80,10 @@ class dta_result_summary {
}
/**
* Decodes the array of JSON detail results returned by the backend service call into the plugin PHP data structure.
* Decodes an array of JSON detail results into the plugin PHP data structure.
*
* @param array $jsonarray Decoded JSON array of results
* @return array Array of DtaResult
* @param array $jsonarray Decoded JSON array of results.
* @return array Array of dta_result objects.
*/
private static function assignsubmission_dta_decode_json_result_array(array $jsonarray): array {
$ret = [];
......@@ -94,13 +92,10 @@ class dta_result_summary {
$value->packagename = $entry->packageName ?? '';
$value->classname = $entry->className ?? '';
$value->name = $entry->name ?? '';
$value->state = $entry->state ?? 0;
$value->failuretype = $entry->failureType ?? '';
$value->failurereason = $entry->failureReason ?? '';
$value->stacktrace = $entry->stacktrace ?? '';
$value->columnnumber = $entry->columnNumber ?? '';
$value->linenumber = $entry->lineNumber ?? '';
$value->position = $entry->position ?? '';
......@@ -113,7 +108,7 @@ class dta_result_summary {
/**
* Returns the number of detail results attached to the summary.
*
* @return int Count of occurrences
* @return int Count of occurrences.
*/
public function assignsubmission_dta_result_count(): int {
return count($this->results);
......@@ -122,13 +117,13 @@ class dta_result_summary {
/**
* Returns the number of detail results with the given state attached to the summary.
*
* @param int $state State ordinal number
* @return int Count of occurrences for the provided state
* @param int $state State ordinal number.
* @return int Count of occurrences for the provided state.
*/
public function assignsubmission_dta_state_occurence_count(int $state): int {
$num = 0;
foreach ($this->results as $r) {
if ($r->state == $state) {
if ($r->state === $state) {
$num++;
}
}
......@@ -138,7 +133,7 @@ class dta_result_summary {
/**
* Returns the number of detail results with compilation errors attached to the summary.
*
* @return int Count of occurrences
* @return int Count of occurrences.
*/
public function assignsubmission_dta_compilation_error_count(): int {
return $this->assignsubmission_dta_state_occurence_count(3);
......@@ -147,7 +142,7 @@ class dta_result_summary {
/**
* Returns the number of detail results with test failures attached to the summary.
*
* @return int Count of occurrences
* @return int Count of occurrences.
*/
public function assignsubmission_dta_failed_count(): int {
return $this->assignsubmission_dta_state_occurence_count(2);
......@@ -156,7 +151,7 @@ class dta_result_summary {
/**
* Returns the number of detail results with successful tests attached to the summary.
*
* @return int Count of occurrences
* @return int Count of occurrences.
*/
public function assignsubmission_dta_successful_count(): int {
return $this->assignsubmission_dta_state_occurence_count(1);
......@@ -165,7 +160,7 @@ class dta_result_summary {
/**
* Returns the number of detail results with an unknown result attached to the summary.
*
* @return int Count of occurrences
* @return int Count of occurrences.
*/
public function assignsubmission_dta_unknown_count(): int {
return $this->assignsubmission_dta_state_occurence_count(0);
......
<?php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - http://moodle.org/.
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
......@@ -14,8 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
defined('MOODLE_INTERNAL') || die();
use assignsubmission_dta\dta_db_utils;
use assignsubmission_dta\dta_backend_utils;
use assignsubmission_dta\dta_view_submission_utils;
......@@ -24,50 +22,58 @@ use assignsubmission_dta\models\dta_result_summary;
use assignsubmission_dta\models\dta_recommendation;
/**
* Library class for DTA submission plugin extending assign submission plugin base class
* Library class for DTA submission plugin extending assign submission plugin base class.
*
* @package assignsubmission_dta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @package assignsubmission_dta
* @copyright 2023 Your Name or Organization
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class assign_submission_dta extends assign_submission_plugin {
/**
* Broadly used in logic, parametrized for easier change.
*/
const ASSIGNSUBMISSION_DTA_COMPONENT_NAME = "assignsubmission_dta";
public const ASSIGNSUBMISSION_DTA_COMPONENT_NAME = 'assignsubmission_dta';
/**
* Draft file area for DTA tests to be uploaded by the teacher.
*/
const ASSIGNSUBMISSION_DTA_DRAFT_FILEAREA_TEST = "tests_draft_dta";
public const ASSIGNSUBMISSION_DTA_DRAFT_FILEAREA_TEST = 'tests_draft_dta';
/**
* File area for DTA tests to be uploaded by the teacher.
*/
const ASSIGNSUBMISSION_DTA_FILEAREA_TEST = "tests_dta";
public const ASSIGNSUBMISSION_DTA_FILEAREA_TEST = 'tests_dta';
/**
* File area for DTA submission assignment.
*/
const ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION = "submissions_dta";
public const ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION = 'submissions_dta';
/**
* Get plugin name
* Get plugin name.
*
* @return string
*/
public function assignsubmission_dta_get_name(): string {
return get_string("pluginname", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME);
return get_string('pluginname', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME);
}
/**
* Get default settings for assignment submission settings
* Get default settings for assignment submission settings.
*
* @param MoodleQuickForm $mform form to add elements to
* @param MoodleQuickForm $mform Form to add elements to.
* @return void
*/
public function assignsubmission_dta_get_settings(MoodleQuickForm $mform): void {
// Add draft filemanager to form.
$mform->addElement(
"filemanager",
'filemanager',
self::ASSIGNSUBMISSION_DTA_DRAFT_FILEAREA_TEST,
get_string("submission_settings_label", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
get_string(
'submission_settings_label',
self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME
),
null,
$this->get_file_options(true)
);
......@@ -77,7 +83,7 @@ class assign_submission_dta extends assign_submission_plugin {
// Form-unique element id to which to add button.
self::ASSIGNSUBMISSION_DTA_DRAFT_FILEAREA_TEST,
// Key.
"submission_settings_label",
'submission_settings_label',
// Language file to use.
self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME
);
......@@ -96,12 +102,15 @@ class assign_submission_dta extends assign_submission_plugin {
/**
* Allows the plugin to update the default values passed into
* the settings form (needed to set up draft areas for editor
* and filemanager elements)
* @param array $defaultvalues
* and filemanager elements).
*
* @param array $defaultvalues Default values to update.
*/
public function data_preprocessing(&$defaultvalues): void {
// Get id of draft area for file manager creation.
$draftitemid = file_get_submitted_draft_itemid(self::ASSIGNSUBMISSION_DTA_DRAFT_FILEAREA_TEST);
$draftitemid = file_get_submitted_draft_itemid(
self::ASSIGNSUBMISSION_DTA_DRAFT_FILEAREA_TEST
);
// Prepare draft area with created draft filearea.
file_prepare_draft_area(
......@@ -117,14 +126,13 @@ class assign_submission_dta extends assign_submission_plugin {
}
/**
* Save settings of assignment submission settings
* Save settings of assignment submission settings.
*
* @param stdClass $data
* @param stdClass $data Form data.
* @return bool
*/
public function assignsubmission_dta_save_settings(stdClass $data): bool {
// If the assignment has no filemanager for our plugin just leave.
// If the assignment has no filemanager for our plugin, just leave.
$draftfilemanagerid = self::ASSIGNSUBMISSION_DTA_DRAFT_FILEAREA_TEST;
if (!isset($data->$draftfilemanagerid)) {
return true;
......@@ -155,7 +163,9 @@ class assign_submission_dta extends assign_submission_plugin {
// Check if a file was uploaded.
if (empty($files)) {
\core\notification::error(get_string("no_testfile_warning", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME));
\core\notification::error(
get_string('no_testfile_warning', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
);
return true;
}
......@@ -163,19 +173,27 @@ class assign_submission_dta extends assign_submission_plugin {
$file = reset($files);
// Send file to backend.
return dta_backend_utils::assignsubmission_dta_send_testconfig_to_backend($this->assignment, $file);
return dta_backend_utils::assignsubmission_dta_send_testconfig_to_backend(
$this->assignment,
$file
);
}
/**
* Add elements to submission form
* Add elements to submission form.
*
* @param mixed $submissionorgrade stdClass|null submission or grade to show in the form
* @param MoodleQuickForm $mform form for adding elements
* @param stdClass $data data for filling the elements
* @param int $userid current user
* @return bool form elements added
* @param stdClass|null $submissionorgrade Submission or grade to show in the form.
* @param MoodleQuickForm $mform Form for adding elements.
* @param stdClass $data Data for filling the elements.
* @param int $userid Current user.
* @return bool True if form elements added.
*/
public function get_form_elements_for_user($submissionorgrade, MoodleQuickForm $mform, stdClass $data, $userid): bool {
public function get_form_elements_for_user(
$submissionorgrade,
MoodleQuickForm $mform,
stdClass $data,
$userid
): bool {
// Prepare submission filearea.
$data = file_prepare_standard_filemanager(
$data,
......@@ -193,20 +211,15 @@ class assign_submission_dta extends assign_submission_plugin {
// Form-unique identifier.
'tasks_filemanager',
// Label to show next to the filemanager.
get_string("submission_label", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
// Attributes.
get_string('submission_label', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
null,
// Options.
$this->get_file_options(false)
);
// Add help button.
$mform->addHelpButton(
// Related form item.
"tasks_filemanager",
// Key.
"submission_label",
// Language file.
'tasks_filemanager',
'submission_label',
self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME
);
......@@ -215,40 +228,46 @@ class assign_submission_dta extends assign_submission_plugin {
/**
* Determines if a submission file area contains any files.
* @param stdClass $submission submission to check
* @return bool true if file count is zero
*
* @param stdClass $submission Submission to check.
* @return bool True if file count is zero.
*/
public function assignsubmission_dta_is_empty(stdClass $submission): bool {
return $this->assignsubmission_dta_count_files($submission->id, self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION) == 0;
return ($this->assignsubmission_dta_count_files(
$submission->id,
self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION
) === 0);
}
/**
* Counts the number of files in a filearea
* Counts the number of files in a filearea.
*
* @param int $submissionid submission id to check
* @param string $areaid filearea id to count
* @return int number of files submitted in the filearea
* @param int $submissionid Submission id to check.
* @param string $areaid Filearea id to count.
* @return int Number of files submitted in the filearea.
*/
private function assignsubmission_dta_count_files(int $submissionid, $areaid) {
private function assignsubmission_dta_count_files(int $submissionid, $areaid): int {
$fs = get_file_storage();
$files = $fs->get_area_files($this->assignment->get_context()->id,
$files = $fs->get_area_files(
$this->assignment->get_context()->id,
self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME,
$areaid,
$submissionid,
'id',
false);
false
);
return count($files);
}
/**
* Save data to the database
* Save data to the database.
*
* @param stdClass $submission
* @param stdClass $data
* @return bool
* @param stdClass $submission Submission object.
* @param stdClass $data Data from the form.
* @return bool True if saved successfully.
*/
public function save(stdClass $submission, stdClass $data) {
public function save(stdClass $submission, stdClass $data): bool {
$data = file_postupdate_standard_filemanager(
$data,
'tasks',
......@@ -267,7 +286,6 @@ class assign_submission_dta extends assign_submission_plugin {
// Get submitted files.
$fs = get_file_storage();
$files = $fs->get_area_files(
// Id of current assignment.
$this->assignment->get_context()->id,
self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME,
self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION,
......@@ -278,15 +296,22 @@ class assign_submission_dta extends assign_submission_plugin {
// Check if a file is uploaded.
if (empty($files)) {
\core\notification::error(get_string("no_submissionfile_warning", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME));
\core\notification::error(
get_string('no_submissionfile_warning', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME)
);
return true;
}
// Get the file.
$file = reset($files);
// Send file to backend.
$response = \assignsubmission_dta\dta_backend_utils::assignsubmission_dta_send_submission_to_backend($this->assignment, $submission->id, $file);
// Send file to backend (split across lines to avoid exceeding length).
$response = \assignsubmission_dta\dta_backend_utils::
assignsubmission_dta_send_submission_to_backend(
$this->assignment,
$submission->id,
$file
);
// With a null response, return an error.
if (is_null($response)) {
......@@ -299,29 +324,35 @@ class assign_submission_dta extends assign_submission_plugin {
// Decode recommendations from response.
$recommendations = dta_recommendation::assignsubmission_dta_decode_json_recommendations($response);
error_log(print_r($recommendations, true));
// Use Moodle debugging instead of error_log/print_r.
debugging('Recommendations: ' . json_encode($recommendations), DEBUG_DEVELOPER);
// Persist new results to database.
dta_db_utils::assignsubmission_dta_store_result_summary_to_database($this->assignment->get_instance()->id, $submission->id, $resultsummary);
// Persist new results to database (split long lines).
dta_db_utils::assignsubmission_dta_store_result_summary_to_database(
$this->assignment->get_instance()->id,
$submission->id,
$resultsummary
);
// Store the array of recommendations in the database.
dta_db_utils::assignsubmission_dta_store_recommendations_to_database($this->assignment->get_instance()->id, $submission->id, $recommendations);
dta_db_utils::assignsubmission_dta_store_recommendations_to_database(
$this->assignment->get_instance()->id,
$submission->id,
$recommendations
);
return true;
}
/**
* Display a short summary of the test results of the submission
* This is displayed as default view, with the option to expand
* to the full detailed results.
* Display a short summary of the test results of the submission.
*
* @param stdClass $submission to show
* @param bool $showviewlink configuration variable to show expand option
* @return string summary results html
* @param stdClass $submission Submission to show.
* @param bool $showviewlink Whether to show expand option.
* @return string Summary results HTML.
*/
public function view_summary(stdClass $submission, & $showviewlink) {
public function view_summary(stdClass $submission, &$showviewlink): string {
$showviewlink = true;
return dta_view_submission_utils::assignsubmission_dta_generate_summary_html(
$this->assignment->get_instance()->id,
$submission->id
......@@ -329,12 +360,12 @@ class assign_submission_dta extends assign_submission_plugin {
}
/**
* Display detailed results
* Display detailed results.
*
* @param stdClass $submission the submission the results are shown for.
* @return string detailed results html
* @param stdClass $submission The submission for which to show results.
* @return string Detailed results HTML.
*/
public function view(stdClass $submission) {
public function view(stdClass $submission): string {
return dta_view_submission_utils::assignsubmission_dta_generate_detail_html(
$this->assignment->get_instance()->id,
$submission->id
......@@ -344,73 +375,77 @@ class assign_submission_dta extends assign_submission_plugin {
/**
* Generate array of allowed file types to upload.
*
* @param bool $settings switch to define if list for assignment settings
* or active submission should be returned
*
* @param bool $settings Whether this is for assignment settings or active submission.
* @return array
*/
private function get_file_options(bool $settings): array {
$fileoptions = [
'subdirs' => 0,
"maxfiles" => 1,
'accepted_types' => ($settings
? [".txt"]
: [
".txt",
".zip",
]),
'return_types' => FILE_INTERNAL,
];
'subdirs' => 0,
'maxfiles' => 1,
'accepted_types' => (
$settings
? ['.txt']
: [
'.txt',
'.zip',
]
),
'return_types' => FILE_INTERNAL,
];
return $fileoptions;
}
/**
* Get file areas returns a list of areas this plugin stores files
* @return array - An array of fileareas (keys) and descriptions (values)
* Get file areas returns a list of areas this plugin stores files.
*
* @return array An array of fileareas (keys) and descriptions (values).
*/
public function get_file_areas() {
public function get_file_areas(): array {
return [
self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION => get_string("dta_submissions_fa", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
self::ASSIGNSUBMISSION_DTA_FILEAREA_TEST => get_string("dta_tests_fa", self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION =>
get_string('dta_submissions_fa', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
self::ASSIGNSUBMISSION_DTA_FILEAREA_TEST =>
get_string('dta_tests_fa', self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME),
];
}
/**
* Produce a list of files suitable for export that represent this feedback or submission
* Produce a list of files suitable for export that represent this feedback or submission.
*
* @param stdClass $submission The submission
* @param stdClass $user The user record - unused
* @return array - return an array of files indexed by filename
* @param stdClass $submission The submission object.
* @param stdClass $user The user record (unused).
* @return array An array of files indexed by filename.
*/
public function get_files(stdClass $submission, stdClass $user) {
public function get_files(stdClass $submission, stdClass $user): array {
$result = [];
$fs = get_file_storage();
$files = $fs->get_area_files($this->assignment->get_context()->id,
$files = $fs->get_area_files(
$this->assignment->get_context()->id,
self::ASSIGNSUBMISSION_DTA_COMPONENT_NAME,
self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION,
$submission->id,
'timemodified',
false);
false
);
foreach ($files as $file) {
foreach ($files as $fileobj) {
// Do we return the full folder path or just the file name?
if (isset($submission->exportfullpath) && $submission->exportfullpath == false) {
$result[$file->get_filename()] = $file;
if (isset($submission->exportfullpath) && $submission->exportfullpath === false) {
$result[$fileobj->get_filename()] = $fileobj;
} else {
$result[$file->get_filepath().$file->get_filename()] = $file;
$result[$fileobj->get_filepath() . $fileobj->get_filename()] = $fileobj;
}
}
return $result;
}
/**
* The plugin is being uninstalled - cleanup
* The plugin is being uninstalled - cleanup.
*
* @return bool
*/
public function delete_instance() {
public function delete_instance(): bool {
dta_db_utils::assignsubmission_dta_uninstall_plugin_cleaup();
return true;
}
}
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