Commit 1772a3e6 authored by Lückemeyer's avatar Lückemeyer
Browse files

added privacy api implementation like in assignsubmission_file

parent e1c80995
Pipeline #8901 passed with stage
No preview for this file type
......@@ -69,7 +69,7 @@ class DtaResult {
/**
* @var $failurereason Reason of test failure if applicable, "" otherwise.
*/
*/
public $failurereason;
/**
......@@ -119,7 +119,7 @@ class DtaResultSummary {
/**
* @var $timestamp Result timestamp for chronological ordering and deletion of previous results.
*/
*/
public $timestamp;
/**
......
<?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/>.
/**
* provider for data privacy
*
* @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\privacy;
defined('MOODLE_INTERNAL') || die();
use core_privacy\local\metadata\collection;
use \core_privacy\local\request\writer;
use \core_privacy\local\request\contextlist;
use \mod_assign\privacy\assign_plugin_request_data;
class provider implements
// This plugin does store personal user data.
\core_privacy\local\metadata\provider,
\mod_assign\privacy\assignsubmission_provider,
\mod_assign\privacy\assignsubmission_user_provider
{
/**
* File area for dta submission assignment.
*/
const ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION = "submissions_dta";
public static function get_metadata(collection $collection): collection {
$collection->add_subsystem_link(
'core_files',
[],
'privacy:metadata:core_files'
);
$collection->add_database_table(
'assignsubmission_dta_summary',
[
'assignmentid' => 'privacy:metadata:assignsubmission_dta_summary:assignmentid',
'submissionid' => 'privacy:metadata:assignsubmission_dta_summary:submissionid',
'timestamp' => 'privacy:metadata:assignsubmission_dta_summary:timestamp',
'global_stacktrace' => 'privacy:metadata:assignsubmission_dta_summary:global_stacktrace',
'successful_competencies' => 'privacy:metadata:assignsubmission_dta_summary:successful_competencies',
'tested_competencies' => 'privacy:metadata:assignsubmission_dta_summary:tested_competencies',
],
'privacy:metadata:assignsubmission_dta_summary'
);
$collection->add_database_table(
'assignsubmission_dta_result',
[
'assignmentid' => 'privacy:metadata:assignsubmission_dta_result:assignmentid',
'submissionid' => 'privacy:metadata:assignsubmission_dta_result:submissionid',
'package_name' => 'privacy:metadata:assignsubmission_dta_result:package_name',
'class_name' => 'privacy:metadata:assignsubmission_dta_result:class_name',
'name' => 'privacy:metadata:assignsubmission_dta_result:name',
'state' => 'privacy:metadata:assignsubmission_dta_result:state',
'failure_type' => 'privacy:metadata:assignsubmission_dta_result:failure_type',
'failure_reason' => 'privacy:metadata:assignsubmission_dta_result:failure_reason',
'stacktrace' => 'privacy:metadata:assignsubmission_dta_result:stacktrace',
'column_number' => 'privacy:metadata:assignsubmission_dta_result:column_number',
'line_number' => 'privacy:metadata:assignsubmission_dta_result:line_number',
'position' => 'privacy:metadata:assignsubmission_dta_result:position',
],
'privacy:metadata:assignsubmission_dta_result'
);
$collection->add_external_location_link('dta_backend', [
'assignmentid' => 'privacy:metadata:assignsubmission_dta_result:assignmentid',
'submissionid' => 'privacy:metadata:assignsubmission_dta_result:submissionid',
'submissioncontent' => 'privacy:metadata:core_files',
],
'privacy:metadata:dta_backend'
);
return $collection;
}
/**
* This is covered by mod_assign provider and the query on assign_submissions.
*
* @param int $userid The user ID that we are finding contexts for.
* @param contextlist $contextlist A context list to add sql and params to for contexts.
*/
public static function get_context_for_userid_within_submission(int $userid, contextlist $contextlist) {
// This is already fetched from mod_assign.
}
/**
* This is also covered by the mod_assign provider and its queries.
*
* @param \mod_assign\privacy\useridlist $useridlist An object for obtaining user IDs of students.
*/
public static function get_student_user_ids(\mod_assign\privacy\useridlist $useridlist) {
// This is already fetched from mod_assign.
}
/**
* If you have tables that contain userids and you can generate entries in your tables without creating an
* entry in the assign_submission table then please fill in this method.
*
* @param userlist $userlist The userlist object
*/
public static function get_userids_from_context(\core_privacy\local\request\userlist $userlist) {
// Not required.
}
/**
* Export all user data for this plugin.
*
* @param assign_plugin_request_data $exportdata Data used to determine which context and user to export and other useful
* information to help with exporting.
*/
public static function export_submission_user_data(assign_plugin_request_data $exportdata) {
// We currently don't show submissions to teachers when exporting their data.
$context = $exportdata->get_context();
if ($exportdata->get_user() != null) {
return null;
}
$user = new \stdClass();
$assign = $exportdata->get_assign();
$submission = $exportdata->get_pluginobject();
$files = get_files($submission, $user);
foreach ($files as $file) {
$userid = $exportdata->get_pluginobject()->userid;
$dtaresultsummary=DBUtils::getresultsummaryfromdatabase($assign->id, $submission->id);
// Submitted file.
writer::with_context($exportdata->get_context())->export_file($exportdata->get_subcontext(), $file)
// DTA result.
->export_related_data($dtaresultsummary);
// Plagiarism data.
$coursecontext = $context->get_course_context();
\core_plagiarism\privacy\provider::export_plagiarism_user_data($userid, $context, $exportdata->get_subcontext(), [
'cmid' => $context->instanceid,
'course' => $coursecontext->instanceid,
'userid' => $userid,
'file' => $file
]);
}
}
/**
* Any call to this method should delete all user data for the context defined in the deletion_criteria.
*
* @param assign_plugin_request_data $requestdata Information useful for deleting user data.
*/
public static function delete_submission_for_context(assign_plugin_request_data $requestdata) {
global $DB;
\core_plagiarism\privacy\provider::delete_plagiarism_for_context($requestdata->get_context());
$fs = get_file_storage();
$fs->delete_area_files($requestdata->get_context()->id, 'assignsubmission_dta', ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION);
$assignmentid = $requestdata->get_assign()->get_instance()->id;
// Delete records from assignsubmission_dta tables.
$DB->delete_records('assignsubmission_dta_result', ['assignmentid' => $assignmentid]);
$DB->delete_records('assignsubmission_dta_summary', ['assignmentid' => $assignmentid]);
}
/**
* A call to this method should delete user data (where practical) using the userid and submission.
*
* @param assign_plugin_request_data $deletedata Details about the user and context to focus the deletion.
*/
public static function delete_submission_for_userid(assign_plugin_request_data $deletedata) {
global $DB;
\core_plagiarism\privacy\provider::delete_plagiarism_for_user($deletedata->get_user()->id, $deletedata->get_context());
$assignmentid = $deletedata->get_assign()->get_instance()->id;
$submissionid = $deletedata->get_pluginobject()->id;
$fs = get_file_storage();
$fs->delete_area_files($deletedata->get_context()->id, 'assignsubmission_dta', ASSIGNSUBMISSION_DTA_FILEAREA_SUBMISSION,
$submissionid);
// Delete records from assignsubmission_dta tables. Also possible with a list as below.
$DB->delete_records('assignsubmission_dta_result', [
'assignmentid' => $assignmentid,
'submissionid' => $submissionid,
]);
$DB->delete_records('assignsubmission_dta_summary', [
'assignmentid' => $assignmentid,
'submissionid' => $submissionid,
]);
}
/**
* Deletes all submissions for the submission ids / userids provided in a context.
* assign_plugin_request_data contains:
* - context
* - assign object
* - submission ids (pluginids)
* - user ids
* @param assign_plugin_request_data $deletedata A class that contains the relevant information required for deletion.
*/
public static function delete_submissions(assign_plugin_request_data $deletedata) {
global $DB;
\core_plagiarism\privacy\provider::delete_plagiarism_for_users($deletedata->get_userids(), $deletedata->get_context());
if (empty($deletedata->get_submissionids())) {
return;
}
$fs = get_file_storage();
list($sql, $params) = $DB->get_in_or_equal($deletedata->get_submissionids(), SQL_PARAMS_NAMED);
$fs->delete_area_files_select($deletedata->get_context()->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA,
$sql, $params);
$params['assignid'] = $deletedata->get_assignid();
$DB->delete_records_select('assignsubmission_dta_result', "assignmentid = :assignid AND submissionid $sql", $params);
$DB->delete_records_select('assignsubmission_dta_summary', "assignmentid = :assignid AND submissionid $sql", $params);
}
/**
* 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 = array();
$fs = get_file_storage();
$files = $fs->get_area_files($this->assignment->get_context()->id,
'assignsubmission_file',
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;
}
}
\ No newline at end of file
......@@ -241,7 +241,7 @@ class view_submission_utils {
// New copy of base attributes array.
$resultrowattributes = $tablerowattributes;
$tmp = "";
$tmp .= html_writer::tag("td", get_string("comp" . $index, self::COMPONENT_NAME), $resultrowattributes);
$tmp .= html_writer::tag("td", get_string("comp" . $index, self::COMPONENT_NAME), $resultrowattributes);
$tmp .= html_writer::tag("td", 100 * floatval($shown) / floatval($comp) . "% " .
"(" . $shown . " / " . $comp . ")", $resultrowattributes);
$tmp .= html_writer::tag("td", get_string("comp_expl" . $index, self::COMPONENT_NAME), $resultrowattributes);
......
<?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
Markdown is supported
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