<?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";
<?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