Commit 11a53f75 authored by Kurzenberger's avatar Kurzenberger
Browse files

deployed the files of the moodledta project

parent 7dec0617
Showing with 1338 additions and 0 deletions
+1338 -0
<?php
// 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
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Upgrade code for install
*
* @package assignsubmission_dta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @copyright Gero Lueckemeyer and student project teams
*/
/**
* Stub for upgrade code
* @param int $oldversion
* @return bool
*/
function xmldb_assignsubmission_dta_upgrade($oldversion) {
global $CFG;
// Currently no adjustments necessary for Moodle upgrades. Works without changes since the first MoJEC version.
return true;
}
<?php
// 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
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Strings for component "assignsubmission_dta", language "en"
*
* @package assignsubmission_dta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @copyright Gero Lueckemeyer and student project teams
*/
// General.
$string["pluginname"] = "Dockerized Testing Agent (DTA)";
$string["enabled"] = $string["pluginname"];
// Dialog field labels.
$string["submission_label"] = "DTA submission configuration or zip-packed project";
$string["submission_label_help"] = "Either upload a single textfile containing one DTA URI pointing to the repository with your submission or pack your project as zip and upload it directly. Using the textfile you can additionally add as many unified-ticketing URI (one per line) as you wish for feedback into one or more ticketsystems.";
$string["submission_settings_label"] = "DTA test configuration";
$string["submission_settings_label_help"] = "single text file with DTA test URI";
$string["enabled_help"] = "If enabled, you will have to upload a textfile containing a valid DTA URI pointing to the repository with your test logic and defining a docker image on dockerhub used as testrunner. Your students will have to either upload their code in a zip archive resembling the expected repository structure or as well by providing a textifle with a valid DTA URI pointing to the repository with their submission logic";
// Content.
$string["tests_successful"] = " successful";
$string["failures"] = " failure";
$string["compilation_errors"] = " compilation error";
$string["unknown_state"] = " with unknown state";
$string["success_competencies"] = "Successfully tested competency profile ";
$string["summary"] = "Summary";
$string["total_items"] = "Total items";
$string["success_rate"] = "Success rate";
$string["details"] = "Details";
$string["competencies"] = "Competencies";
$string["package_name"] = "Package Name";
$string["unit_name"] = "Unit Name";
$string["test_name"] = "Test Name";
$string["status"] = "Status";
$string["failure_type"] = "Failure Type";
$string["failure_reason"] = "Failure Reason";
$string["line_no"] = "Line Number";
$string["col_no"] = "Column Number";
$string["pos"] = "Position";
$string["stacktrace"] = "Stack Trace";
// Comeptencies.
$string["comp_statement"] = "Statement";
$string["comp_block"] = "Block";
$string["comp_flow"] = "Flow of Control";
$string["comp_loop"] = "Repetition";
$string["comp_const"] = "Constant";
$string["comp_var"] = "Variable";
$string["comp_type"] = "Type";
$string["comp_datastructure"] = "Data Structure";
$string["comp_interface"] = "Interface";
$string["comp_unit"] = "Unit of Code";
$string["comp_proc_usage"] = "Procedure Usage";
$string["comp_proc_sign"] = "Procedure Signature";
$string["comp_library"] = "Library Usage";
$string["comp_ext_api"] = "External API Usage";
$string["comp_simple"] = "Simplicity";
$string["comp_abstraction"] = "Abstraction";
// Competencies for index calculation.
$string["comp0"] = $string["comp_statement"];
$string["comp1"] = $string["comp_block"];
$string["comp2"] = $string["comp_flow"];
$string["comp3"] = $string["comp_loop"];
$string["comp4"] = $string["comp_const"];
$string["comp5"] = $string["comp_var"];
$string["comp6"] = $string["comp_type"];
$string["comp7"] = $string["comp_datastructure"];
$string["comp8"] = $string["comp_interface"];
$string["comp9"] = $string["comp_unit"];
$string["comp10"] = $string["comp_proc_usage"];
$string["comp11"] = $string["comp_proc_sign"];
$string["comp12"] = $string["comp_library"];
$string["comp13"] = $string["comp_ext_api"];
$string["comp14"] = $string["comp_simple"];
$string["comp15"] = $string["comp_abstraction"];
// Competency explanations.
$string["comp_statement_expl"] = "formulate a syntactically correct statement that contributes to the solution of the given problem.";
$string["comp_block_expl"] = "structure code into syntactically correct small unnamed units that contribute to the solution of the given problem.";
$string["comp_flow_expl"] = "formulate syntax elements guiding the control flow such that it contributes to the solution of the given problem.";
$string["comp_loop_expl"] = "use syntax elements repeating statements such that it contributes to the solution of the given problem.";
$string["comp_const_expl"] = "identify and syntactically correctly define constants that contribute to the understanding and solution of the given problem.";
$string["comp_var_expl"] = "identify and syntactically correctly define variables that contribute to the solution of the given problem.";
$string["comp_type_expl"] = "define and/or choose appropriate data types for data elements such that they contribute to the solution of the given problem.";
$string["comp_datastructure_expl"] = "define and/or choose appropriate data structures for data elements such that they contribute to the solution of the given problem.";
$string["comp_interface_expl"] = "define and use interfaces for larger units of code such that it contributes to the solution of the given problem.";
$string["comp_unit_expl"] = "define and larger units of code such that it contributes to the solution of the given problem.";
$string["comp_proc_usage_expl"] = "use existing named structure blocks with a pre-defined behavior and signature such that it contributes to the solution of the given problem.";
$string["comp_proc_sign_expl"] = "define named structure blocks with a pre-defined behavior and signature such that it contributes to the solution of the given problem.";
$string["comp_library_expl"] = "use existing larger collections of named structure blocks with a pre-defined behavior and signature such that it contributes to the solution of the given problem.";
$string["comp_ext_api_expl"] = "use standardized existing external collections of named structure blocks with a pre-defined behavior and signature such that it contributes to the solution of the given problem.";
$string["comp_simple_expl"] = "create a simple solution of the given problem.";
$string["comp_abstraction_expl"] = "create a sufficiently abstract solution for the given problem.";
// Competency explanations for index calculations.
$string["comp_expl0"] = $string["comp_statement_expl"];
$string["comp_expl1"] = $string["comp_block_expl"];
$string["comp_expl2"] = $string["comp_flow_expl"];
$string["comp_expl3"] = $string["comp_loop_expl"];
$string["comp_expl4"] = $string["comp_const_expl"];
$string["comp_expl5"] = $string["comp_var_expl"];
$string["comp_expl6"] = $string["comp_type_expl"];
$string["comp_expl7"] = $string["comp_datastructure_expl"];
$string["comp_expl8"] = $string["comp_interface_expl"];
$string["comp_expl9"] = $string["comp_unit_expl"];
$string["comp_expl10"] = $string["comp_proc_usage_expl"];
$string["comp_expl11"] = $string["comp_proc_sign_expl"];
$string["comp_expl12"] = $string["comp_library_expl"];
$string["comp_expl13"] = $string["comp_ext_api_expl"];
$string["comp_expl14"] = $string["comp_simple_expl"];
$string["comp_expl15"] = $string["comp_abstraction_expl"];
// Warnings.
$string["no_testfile_warning"] = "Submission type is \"Dockerized Testing Agent\" but no configuration file uploaded";
// Error messages.
$string["backendHost_not_set"] = "The Dockerized Testing Agent backend URL is not configured";
$string["no_submissionfile_warning"] = "Submission type is \"Dockerized Testing Agent\" but no configuration file or submission archive uploaded";
$string["http_client_error_msg"] = "A client error occured (HTTP 4xx)";
$string["http_server_error_msg"] = "A server error occured (HTTP 5xx)";
$string["http_unknown_error_msg"] = "An unknown HTTP error occured on backend transfer";
// Admin settings.
$string["default"] = "Enabled by default";
$string["default_help"] = "If set, this submission method will be enabled by default for all new assignments.";
$string["backendHost"] = "Backend Server Address";
$string["backendHost_help"] = "Address/Name and Port of backend server";
// Database field descriptions for privacy API.
$string["privacy:metadata:core_files"] = "Moodle core files.";
$string["privacy:metadata:assignsubmission_dta_summary:assignmentid"] = "ID of the assignment";
$string["privacy:metadata:assignsubmission_dta_summary:submissionid"] = "ID of the submission";
$string["privacy:metadata:assignsubmission_dta_summary:timestamp"] = "Date and time of the submission";
$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"] = "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";
$string["privacy:metadata:assignsubmission_dta_result:name"] = "Name of individual test";
$string["privacy:metadata:assignsubmission_dta_result:state"] = "State of individual test";
$string["privacy:metadata:assignsubmission_dta_result:failure_type"] = "Failure type of individual test";
$string["privacy:metadata:assignsubmission_dta_result:failure_reason"] = "Failure reason of individual test";
$string["privacy:metadata:assignsubmission_dta_result:stacktrace"] = "Stack trace of failed compilation or individual test";
$string["privacy:metadata:assignsubmission_dta_result:column_number"] = "Column number of failed individual compilation or test";
$string["privacy:metadata:assignsubmission_dta_result:line_number"] = "Line number 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:dta_backend"] = "Dockerized Test Agent (DTA) backend ReST web service";
<?php
// 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
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains the moodle hooks for the submission DTA plugin
*
* @package assignsubmission_dta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @copyright Gero Lueckemeyer and student project teams
*/
/**
* Serves assignment submissions and other files.
*
* @param mixed $course course or id of the course
* @param mixed $cm course module or id of the course module
* @param context $context
* @param string $filearea
* @param array $args
* @param bool $forcedownload
* @return bool false if file not found, does not return if found - just send the file
*/
function assignsubmission_dta_pluginfile(
$course,
$cm,
context $context,
$filearea,
$args,
$forcedownload
) {
global $DB, $CFG;
if ($context->contextlevel != CONTEXT_MODULE) {
return false;
}
require_login($course, false, $cm);
$itemid = (int)array_shift($args);
$record = $DB->get_record('assign_submission',
['id' => $itemid],
'userid, assignment, groupid',
MUST_EXIST);
$userid = $record->userid;
$groupid = $record->groupid;
require_once($CFG->dirroot . '/mod/assign/locallib.php');
$assign = new assign($context, $cm, $course);
if ($assign->get_instance()->id != $record->assignment) {
return false;
}
if ($assign->get_instance()->teamsubmission &&
!$assign->can_view_group_submission($groupid)) {
return false;
}
if (!$assign->get_instance()->teamsubmission &&
!$assign->can_view_submission($userid)) {
return false;
}
$relativepath = implode('/', $args);
$fullpath = "/{$context->id}/assignsubmission_dta/$filearea/$itemid/$relativepath";
$fs = get_file_storage();
if (!($file = $fs->get_file_by_hash(sha1($fullpath))) || $file->is_directory()) {
return false;
}
// Download MUST be forced - security!
send_stored_file($file, 0, 0, true);
}
<?php
// 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
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// 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();
// Import various entity and application logic files.
require_once($CFG->dirroot . '/mod/assign/submission/dta/models/DtaResult.php');
require_once($CFG->dirroot . '/mod/assign/submission/dta/classes/database.php');
require_once($CFG->dirroot . '/mod/assign/submission/dta/classes/backend.php');
require_once($CFG->dirroot . '/mod/assign/submission/dta/classes/view.php');
/**
* 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
*/
class assign_submission_dta extends assign_submission_plugin {
/**
* Broadly used in logic, parametrized for easier change.
*/
const 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";
/**
* File area for dta tests to be uploaded by the teacher.
*/
const ASSIGNSUBMISSION_DTA_FILEAREA_TEST = "tests_dta";
/**
* File area for dta submission assignment.
*/
const ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION = "submissions_dta";
/**
* get plugin name
* @return string
*/
public function get_name(): string {
return get_string("pluginname", self::COMPONENT_NAME);
}
/**
* Get default settings for assignment submission settings
*
* @param MoodleQuickForm $mform form to add elements to
* @return void
*/
public function get_settings(MoodleQuickForm $mform): void {
// Add draft filemanager to form.
$mform->addElement(
"filemanager",
self::ASSIGNSUBMISSION_DTA_DRAFT_FILEAREA_TEST,
get_string("submission_settings_label", self::COMPONENT_NAME),
null,
$this->get_file_options(true)
);
// Add help button to added filemanager.
$mform->addHelpButton(
// Form-unique element id to which to add button.
self::ASSIGNSUBMISSION_DTA_DRAFT_FILEAREA_TEST,
// Key.
"submission_settings_label",
// Language file to use.
self::COMPONENT_NAME
);
// Only show filemanager if plugin is enabled.
$mform->hideIf(
// Form-unique element id to hide.
self::ASSIGNSUBMISSION_DTA_DRAFT_FILEAREA_TEST,
// Condition to check.
self::COMPONENT_NAME . '_enabled',
// State to match for hiding.
'notchecked'
);
}
/**
* Allows the plugin to update the defaultvalues passed in to
* the settings form (needed to set up draft areas for editor
* and filemanager elements)
* @param array $defaultvalues
*/
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);
// Prepare draft area with created draft filearea.
file_prepare_draft_area(
$draftitemid,
$this->assignment->get_context()->id,
self::COMPONENT_NAME,
self::ASSIGNSUBMISSION_DTA_FILEAREA_TEST,
0,
['subdirs' => 0]
);
$defaultvalues[self::ASSIGNSUBMISSION_DTA_DRAFT_FILEAREA_TEST] = $draftitemid;
}
/**
* Save settings of assignment submission settings
*
* @param stdClass $data
* @return bool
*/
public function save_settings(stdClass $data): bool {
// If the assignment has no filemanager for our plugin just leave.
$draftfilemanagerid = self::ASSIGNSUBMISSION_DTA_DRAFT_FILEAREA_TEST;
if (!isset($data->$draftfilemanagerid)) {
return true;
}
// Store files from draft filearea to final one.
file_save_draft_area_files(
// Form-unique element id of draft filemanager from the edit.
$data->$draftfilemanagerid,
// Id of the assignment in edit.
$this->assignment->get_context()->id,
self::COMPONENT_NAME,
self::ASSIGNSUBMISSION_DTA_FILEAREA_TEST,
0
);
// Get files from proper filearea.
$fs = get_file_storage();
$files = $fs->get_area_files(
// Id of the current assignment.
$this->assignment->get_context()->id,
self::COMPONENT_NAME,
self::ASSIGNSUBMISSION_DTA_FILEAREA_TEST,
0,
'id',
false
);
// Check if a file was uploaded.
if (empty($files)) {
\core\notification::error(get_string("no_testfile_warning", self::COMPONENT_NAME));
return true;
}
// Get the file.
$file = reset($files);
// Send file to backend.
return DtaBackendUtils::sendtestconfigtobackend($this->assignment, $file);
}
/**
* 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
*/
public function get_form_elements_for_user($submissionorgrade, MoodleQuickForm $mform, stdClass $data, $userid): bool {
// Prepare submission filearea.
$data = file_prepare_standard_filemanager(
$data,
'tasks',
$this->get_file_options(false),
$this->assignment->get_context(),
self::COMPONENT_NAME,
self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION,
$submissionorgrade ? $submissionorgrade->id : 0
);
// Add filemanager to form.
$mform->addElement(
'filemanager',
// Form-unique identifier.
'tasks_filemanager',
// Label to show next to the filemanager.
get_string("submission_label", self::COMPONENT_NAME),
// Attributes.
null,
// Options.
$this->get_file_options(false)
);
// Add help button.
$mform->addHelpButton(
// Related form item.
"tasks_filemanager",
// Key.
"submission_label",
// Language file.
self::COMPONENT_NAME
);
return true;
}
/**
* Determines if a submission file area contains any files.
* @param stdClass $submission submission to check
* @return bool true if file count is zero
*/
public function is_empty(stdClass $submission): bool {
return $this->count_files($submission->id, self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION) == 0;
}
/**
* 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
*/
private function count_files(int $submissionid, $areaid) {
$fs = get_file_storage();
$files = $fs->get_area_files($this->assignment->get_context()->id,
self::COMPONENT_NAME,
$areaid,
$submissionid,
'id',
false);
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
);
// 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 the file.
$file = reset($files);
// Send file to backend.
$response = DtaBackendUtils::sendsubmissiontobackend($this->assignment, $submission->id, $file);
// With a null response, return an error.
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;
}
/**
* Display a short summary of the test results of the submission
* This is diplayed as default view, with the option to expand
* to the full detailed results.
*
* @param stdClass $submission to show
* @param bool $showviewlink configuration variable to show expand option
* @return string summary results html
*/
public function view_summary(stdClass $submission, & $showviewlink) {
$showviewlink = true;
return view_submission_utils::generatesummaryhtml(
$this->assignment->get_instance()->id,
$submission->id
);
}
/**
* Display detailed results
*
* @param stdClass $submission the submission the results are shown for.
* @return string detailed results html
*/
public function view(stdClass $submission) {
return view_submission_utils::generatedetailhtml(
$this->assignment->get_instance()->id,
$submission->id
);
}
/**
* generate array of allowed filetypes to upload.
*
* @param bool $settings switch to define if list for assignment settings
* or active submission should be returned
*
* @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,
];
return $fileoptions;
}
/**
* 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() {
return [
self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION => get_string("dta_submissions_fa", self::COMPONENT_NAME),
self::ASSIGNSUBMISSION_DTA_FILEAREA_TEST => get_string("dta_tests_fa", self::COMPONENT_NAME),
];
}
/**
* 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
*/
public function get_files(stdClass $submission, stdClass $user) {
$result = [];
$fs = get_file_storage();
$files = $fs->get_area_files($this->assignment->get_context()->id,
self::COMPONENT_NAME,
self::ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION,
$submission->id,
'timemodified',
false);
foreach ($files as $file) {
// Do we return the full folder path or just the file name?
if (isset($submission->exportfullpath) && $submission->exportfullpath == false) {
$result[$file->get_filename()] = $file;
} else {
$result[$file->get_filepath().$file->get_filename()] = $file;
}
}
return $result;
}
/**
* The plugin is beeing uninstalled - cleanup
*
* @return bool
*/
public function delete_instance() {
DbUtils::uninstallplugincleanup();
return true;
}
}
<?php
// 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
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* entity classes for DTA submission plugin result summary and test results
*
* @package assignsubmission_dta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @copyright Gero Lueckemeyer and student project teams
*/
defined('MOODLE_INTERNAL') || die();
/**
* entity class for DTA submission plugin result
*
* @package assignsubmission_dta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @copyright Gero Lueckemeyer and student project teams
*/
class DtaResult {
/**
* Broadly used in logic, parametrized for easier change.
*/
const COMPONENT_NAME = "assignsubmission_dta";
/**
* @var $packagename Package name of the test.
*/
public $packagename;
/**
* @var $classname Unit name of the test.
*/
public $classname;
/**
* @var $name Name of the test.
*/
public $name;
/**
* @var $state State is defined like below
*
* 0 UNKNOWN
* 1 SUCCESS
* 2 FAILURE
* 3 COMPILATIONERROR
*/
public $state;
/**
* @var $failuretype Type of test failure if applicable, "" otherwise.
*/
public $failuretype;
/**
* @var $failurereason Reason of test failure if applicable, "" otherwise.
*/
public $failurereason;
/**
* @var $stacktrace Stack trace of test failure if applicable, "" otherwise.
*/
public $stacktrace;
/**
* @var $columnnumber Column number of compile failure if applicable, "" otherwise.
*/
public $columnnumber;
/**
* @var $linenumber Line number of compile failure if applicable, "" otherwise.
*/
public $linenumber;
/**
* @var $position Position of compile failure if applicable, "" otherwise.
*/
public $position;
/**
* Returns the name of a state with the given number of display.
* @param int $state number of the state
* @return string name of state as defined
*/
public static function getstatename(int $state): string {
if ($state == 1) {
return get_string("tests_successful", self::COMPONENT_NAME);
} else if ($state == 2) {
return get_string("failures", self::COMPONENT_NAME);
} else if ($state == 3) {
return get_string("compilation_errors", self::COMPONENT_NAME);
} else {
return get_string("unknown_state", self::COMPONENT_NAME);
}
}
}
/**
* entity class for DTA submission plugin result
*
* @package assignsubmission_dta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @copyright Gero Lueckemeyer and student project teams
*/
class DtaResultSummary {
/**
* @var $timestamp Result timestamp for chronological ordering and deletion of previous results.
*/
public $timestamp;
/**
* @var $globalstacktrace Global stack trace if applicable, "" otherwise.
*/
public $globalstacktrace;
/**
* @var $successfultestcompetencies Successfully tested competencies according to tests and weights, "" otherwise.
*/
public $successfultestcompetencies;
/**
* @var overalltestcompetencies Overall tested competencies according to tests and weights, "" otherwise.
*/
public $overalltestcompetencies;
/**
* @var results List of detail results.
*/
public $results;
/**
* Decodes the JSON result summary returned by the backend service call into the plugin PHP data structure.
* @param string $jsonstring jsonString containing DtaResultSummary
* @return DtaResultSummary the result summary
*/
public static function decodejson(string $jsonstring): DtaResultSummary {
$response = json_decode($jsonstring);
$summary = new DtaResultSummary();
$summary->timestamp = $response->timestamp;
$summary->globalstacktrace = $response->globalstacktrace;
$summary->successfultestcompetencies = $response->successfulTestCompetencyProfile;
$summary->overalltestcompetencies = $response->overallTestCompetencyProfile;
$summary->results = self::decodejsonresultarray($response->results);
return $summary;
}
/**
* 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
* @return array of DtaResult
*/
private static function decodejsonresultarray($jsonarray): array {
$ret = [];
foreach ($jsonarray as $entry) {
$value = new DtaResult();
$value->packagename = $entry->packageName;
$value->classname = $entry->className;
$value->name = $entry->name;
$value->state = $entry->state;
$value->failuretype = $entry->failureType;
$value->failurereason = $entry->failureReason;
$value->stacktrace = $entry->stacktrace;
$value->columnnumber = $entry->columnNumber;
$value->linenumber = $entry->lineNumber;
$value->position = $entry->position;
$ret[] = $value;
}
return $ret;
}
/**
* Returns the number of detail results attached to the summary.
* @return int count of occurences
*/
public function resultcount(): int {
return count($this->results);
}
/**
* Returns the number of detail results with the given state attached to the summary.
* @param int $state state ordinal number
* @return int count of occurences provided state has
*/
public function stateoccurencecount(int $state): int {
$num = 0;
foreach ($this->results as $r) {
if ($r->state == $state) {
$num++;
}
}
return $num;
}
/**
* Returns the number of detail results with compilation errors attached to the summary.
* @return int count of occurences
*/
public function compilationerrorcount(): int {
return $this->stateoccurencecount(3);
}
/**
* Returns the number of detail results with test failures attached to the summary.
* @return int count of occurences
*/
public function failedcount(): int {
return $this->stateoccurencecount(2);
}
/**
* Returns the number of detail results with successful tests attached to the summary.
* @return int count of occurences
*/
public function successfulcount(): int {
return $this->stateoccurencecount(1);
}
/**
* Returns the number of detail results with an unknown result - mostly due to compile errors - attached to the summary.
* @return int count of occurences
*/
public function unknowncount(): int {
return $this->stateoccurencecount(0);
}
}
<?php
// 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
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file defines the admin settings for this plugin
*
* @package assignsubmission_dta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @copyright Gero Lueckemeyer and student project teams
*/
defined('MOODLE_INTERNAL') || die();
$settings->add(new admin_setting_configcheckbox("assignsubmission_dta/default",
new lang_string("default", "assignsubmission_dta"),
new lang_string("default_help", "assignsubmission_dta"), 0));
$settings->add(new admin_setting_configtext("assignsubmission_dta/backendHost",
new lang_string("backendHost", "assignsubmission_dta"),
new lang_string("backendHost_help", "assignsubmission_dta"), "http://dtabackend:8080"));
/* Prevent word breaking in the grading table */
.dtaSubmissionSummary {
white-space: nowrap;
}
.dtaSubmissionSummary,
.dtaSubmissionDetails {
margin-top: 15px;
}
/* empty div between summary and detail table */
.dtaSpacer {
margin-top: 30px;
}
/****************************************************************
* Layout for the Detail view
****************************************************************/
.dtaTable {
display: inline-block;
max-width: 100%;
overflow: auto;
background: white !important;
border-radius: .1rem;
box-shadow: 0 .2rem .5rem rgba(0,0,0,.05),0 0 .05rem rgba(0,0,0,.1);
overflow-x: hidden;
}
.dtaTableHeaderRow {
font-weight: bold;
color: white !important;
background-color: gray !important;
}
.dtaTableRow {
background-color: unset !important;
border-top: .05rem solid lightgray;
}
.dtaTableHeaderRow th,
.dtaTableRow td {
padding: .9375em 1.25em;
}
.dtaStacktraceDetails {
max-height: 300px;
max-width: 70%;
overflow: auto;
}
.dtaResultUnknown {
border-left: 10px solid gray;
}
.dtaResultSuccess {
border-left: 10px solid green;
}
.dtaResultFailure {
border-left: 10px solid orange;
}
.dtaResultCompilationError {
border-left: 10px solid red;
}
.dtaTableRow:hover {
background-color: lightgray !important;
}
.dtaTableSpacer {
border-bottom: 2px solid darkgray;
}
<?php
// 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
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains the version information for the onlinetext DTA plugin
*
* @package assignsubmission_dta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @copyright Gero Lueckemeyer and student project teams
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2023123001;
$plugin->requires = 2020061525; // Moodle 3.9 LTS. Older unsupported versions from the 3.x branch should also work.
$plugin->component = 'assignsubmission_dta';
$plugin->maturity = MATURITY_STABLE;
$plugin->release = "3.1.0";
dtt::https://transfer.hft-stuttgart.de/gitlab/dtt/example_openjdk11-junit5-calculator-test.git::none::none::hftstuttgart/dta-jdk17-junit5-testrunner:latest
<?php
// Set this if you want to run the script for one component only. Otherwise leave empty.
$CHECK_COMPONENT = '';
define('CLI_SCRIPT', true);
require_once('config.php');
$user = \core_user::get_user(2);
\core\session\manager::init_empty_session();
\core\session\manager::set_user($user);
$rc = new \ReflectionClass(\core_privacy\manager::class);
$rcm = $rc->getMethod('get_component_list');
$rcm->setAccessible(true);
$manager = new \core_privacy\manager();
$components = $rcm->invoke($manager);
$list = (object) [
'good' => [],
'bad' => [],
];
foreach ($components as $component) {
if ($CHECK_COMPONENT && $component !== $CHECK_COMPONENT) {
continue;
}
$compliant = $manager->component_is_compliant($component);
if ($compliant) {
$list->good[] = $component;
} else {
$list->bad[] = $component;
}
}
echo "The following plugins are not compliant:\n";
echo "=> " . implode("\n=> ", array_values($list->bad)) . "\n";
echo "\n";
echo "Testing the compliant plugins:\n";
foreach ($list->good as $component) {
$classname = \core_privacy\manager::get_provider_classname_for_component($component);
echo "== {$component} ($classname) ==\n";
if (check_implements($component, \core_privacy\local\metadata\null_provider::class)) {
echo " Claims not to store any data with reason:\n";
echo " '" . get_string($classname::get_reason(), $component) . "'\n";
}
else if (check_implements($component, \core_privacy\local\metadata\provider::class)) {
$collection = new \core_privacy\local\metadata\collection($component);
$classname::get_metadata($collection);
$count = count($collection->get_collection());
echo " Found {$count} items of metadata\n";
if (empty($count)) {
echo "!!! No metadata found!!! This an error.\n";
}
if (check_implements($component, \core_privacy\local\request\user_preference_provider::class)) {
$userprefdescribed = false;
foreach ($collection->get_collection() as $item) {
if ($item instanceof \core_privacy\local\metadata\types\user_preference) {
$userprefdescribed = true;
echo " ".$item->get_name()." : ".get_string($item->get_summary(), $component) . "\n";
}
}
if (!$userprefdescribed) {
echo "!!! User preference found, but was not described in metadata\n";
}
}
if (check_implements($component, \core_privacy\local\request\core_user_data_provider::class)) {
// No need to check the return type - it's enforced by the interface.
$contextlist = $classname::get_contexts_for_userid($user->id);
$approvedcontextlist = new \core_privacy\local\request\approved_contextlist($user, $contextlist->get_component(), $contextlist->get_contextids());
if (count($approvedcontextlist)) {
$classname::export_user_data($approvedcontextlist);
echo " Successfully ran a test export\n";
} else {
echo " Nothing to export.\n";
}
}
if (check_implements($component, \core_privacy\local\request\shared_data_provider::class)) {
echo " This is a shared data provider\n";
}
}
}
echo "\n\n== Done ==\n";
function check_implements($component, $interface) {
$manager = new \core_privacy\manager();
$rc = new \ReflectionClass(\core_privacy\manager::class);
$rcm = $rc->getMethod('component_implements');
$rcm->setAccessible(true);
return $rcm->invoke($manager, $component, $interface);
}
\ No newline at end of file
<?php
// 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
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
define('CLI_SCRIPT', true);
require_once('config.php');
require_once("$CFG->libdir/clilib.php");
list($options, $unrecognized) = cli_get_params(
[
'username' => '',
'userid' => '',
],
[]
);
$user = null;
$username = $options['username'];
$userid = $options['userid'];
if (!empty($options['username'])) {
$user = \core_user::get_user_by_username($options['username']);
} else if (!empty($options['userid'])) {
$user = \core_user::get_user($options['userid']);
}
while (empty($user)) {
if (!empty($username)) {
echo "Unable to find a user with username '{$username}'.\n";
echo "Try again.\n";
} else if (!empty($userid)) {
echo "Unable to find a user with userid '{$userid}'.\n";
echo "Try again.\n";
}
$username = readline("Username: ");
$user = \core_user::get_user_by_username($username);
}
echo "Processing delete for " . fullname($user) . "\n";
\core\session\manager::init_empty_session();
\core\session\manager::set_user($user);
$manager = new \core_privacy\manager();
$approvedlist = new \core_privacy\local\request\contextlist_collection($user->id);
$trace = new text_progress_trace();
$contextlists = $manager->get_contexts_for_userid($user->id, $trace);
foreach ($contextlists as $contextlist) {
$approvedlist->add_contextlist(new \core_privacy\local\request\approved_contextlist(
$user,
$contextlist->get_component(),
$contextlist->get_contextids()
));
}
$manager->delete_data_for_user($approvedlist, $trace);
\ No newline at end of file
<?php
// 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
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Helper utility to perform a test export.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('CLI_SCRIPT', true);
require_once('config.php');
require_once("$CFG->libdir/clilib.php");
list($options, $unrecognized) = cli_get_params(
[
'username' => '',
'userid' => '',
],
[]
);
$user = null;
$username = $options['username'];
$userid = $options['userid'];
if (!empty($options['username'])) {
$user = \core_user::get_user_by_username($options['username']);
} else if (!empty($options['userid'])) {
$user = \core_user::get_user($options['userid']);
}
while (empty($user)) {
if (!empty($username)) {
echo "Unable to find a user with username '{$username}'.\n";
echo "Try again.\n";
} else if (!empty($userid)) {
echo "Unable to find a user with userid '{$userid}'.\n";
echo "Try again.\n";
}
$username = readline("Username: ");
$user = \core_user::get_user_by_username($username);
}
echo "Processing export for " . fullname($user) . "\n";
\core\session\manager::init_empty_session();
\core\session\manager::set_user($user);
$PAGE = new moodle_page();
$OUTPUT = new core_renderer($PAGE, RENDERER_TARGET_GENERAL);
$manager = new \core_privacy\manager();
$approvedlist = new \core_privacy\local\request\contextlist_collection($user->id);
$contextlists = $manager->get_contexts_for_userid($user->id);
foreach ($contextlists as $contextlist) {
$approvedlist->add_contextlist(new \core_privacy\local\request\approved_contextlist(
$user,
$contextlist->get_component(),
$contextlist->get_contextids()
));
}
$exportedcontent = $manager->export_user_data($approvedlist);
$basedir = make_temp_directory('privacy');
$exportpath = make_unique_writable_directory($basedir, true);
$fp = get_file_packer();
$fp->extract_to_pathname($exportedcontent, $exportpath);
echo "\n";
echo "== File export was uncompressed to {$exportpath}\n";
echo "============================================================================\n";
\ No newline at end of file
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