Skip to content

Commit

Permalink
MDL-62135 tool_log: Implement privacy API
Browse files Browse the repository at this point in the history
  • Loading branch information
FMCorz committed May 2, 2018
1 parent 1e65154 commit 8ff7363
Show file tree
Hide file tree
Showing 6 changed files with 645 additions and 1 deletion.
148 changes: 148 additions & 0 deletions admin/tool/log/classes/local/privacy/helper.php
@@ -0,0 +1,148 @@
<?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/>.

/**
* Privacy helper.
*
* @package tool_log
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

namespace tool_log\local\privacy;
defined('MOODLE_INTERNAL') || die();

use core_privacy\local\request\transform;

/**
* Privacy helper class.
*
* @package tool_log
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class helper {

/**
* Returns an event from a standard record.
*
* @see \logstore_standard\log\store::get_log_event()
* @param object $data Log data.
* @return \core\event\base
*/
protected static function restore_event_from_standard_record($data) {
$extra = ['origin' => $data->origin, 'ip' => $data->ip, 'realuserid' => $data->realuserid];
$data = (array) $data;
$id = $data['id'];
$data['other'] = unserialize($data['other']);
if ($data['other'] === false) {
$data['other'] = [];
}
unset($data['origin']);
unset($data['ip']);
unset($data['realuserid']);
unset($data['id']);

if (!$event = \core\event\base::restore($data, $extra)) {
return null;
}

return $event;
}

/**
* Transform a standard log record for a user.
*
* @param object $record The record.
* @param int $userid The user ID.
* @return array
*/
public static function transform_standard_log_record_for_userid($record, $userid) {

// Restore the event to try to get the name, description and other field.
$restoredevent = static::restore_event_from_standard_record($record);
if ($restoredevent) {
$name = $restoredevent->get_name();
$description = $restoredevent->get_description();
$other = $restoredevent->other;

} else {
$name = $record->eventname;
$description = "Unknown event ({$name})";
$other = unserialize($record->other);
}

$realuserid = $record->realuserid;
$isauthor = $record->userid == $userid;
$isrelated = $record->relateduserid == $userid;
$isrealuser = $realuserid == $userid;
$ismasqueraded = $realuserid !== null && $record->userid != $realuserid;
$ismasquerading = $isrealuser && !$isauthor;
$isanonymous = $record->anonymous;

$data = [
'name' => $name,
'description' => $description,
'timecreated' => transform::datetime($record->timecreated),
'ip' => $record->ip,
'origin' => static::transform_origin($record->origin),
'other' => $other ? $other : []
];

if ($isanonymous) {
$data['action_was_done_anonymously'] = transform::yesno($isanonymous);
}
if ($isauthor || !$isanonymous) {
$data['authorid'] = transform::user($record->userid);
$data['author_of_the_action_was_you'] = transform::yesno($isauthor);
}

if ($record->relateduserid) {
$data['relateduserid'] = transform::user($record->relateduserid);
$data['related_user_was_you'] = transform::yesno($isrelated);
}

if ($ismasqueraded) {
$data['author_of_the_action_was_masqueraded'] = transform::yesno(true);
if ($ismasquerading || !$isanonymous) {
$data['masqueradinguserid'] = transform::user($realuserid);
$data['masquerading_user_was_you'] = transform::yesno($ismasquerading);
}
}

return $data;
}

/**
* Transform origin.
*
* @param string $origin The page request origin.
* @return string
*/
public static function transform_origin($origin) {
switch ($origin) {
case 'cli':
case 'restore':
case 'web':
case 'ws':
return get_string('privacy:request:origin:' . $origin, 'tool_log');
break;
}
return $origin;
}
}
78 changes: 78 additions & 0 deletions admin/tool/log/classes/local/privacy/logstore_provider.php
@@ -0,0 +1,78 @@
<?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/>.

/**
* Logstore provider interface.
*
* @package tool_log
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

namespace tool_log\local\privacy;
defined('MOODLE_INTERNAL') || die();

use context;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\approved_contextlist;

/**
* Logstore provider interface.
*
* Logstore subplugins providers must implement this interface.
*
* @package tool_log
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
interface logstore_provider extends \core_privacy\local\request\plugin\subplugin_provider {

/**
* Add contexts that contain user information for the specified user.
*
* @param contextlist $contextlist The contextlist to add the contexts to.
* @param int $userid The user to find the contexts for.
* @return void
*/
public static function add_contexts_for_userid(contextlist $contextlist, $userid);

/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
* @return void
*/
public static function export_user_data(approved_contextlist $contextlist);

/**
* Delete all data for all users in the specified context.
*
* @param context $context The specific context to delete data for.
* @return void
*/
public static function delete_data_for_all_users_in_context(context $context);

/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
* @return void
*/
public static function delete_data_for_user(approved_contextlist $contextlist);

}
@@ -0,0 +1,123 @@
<?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/>.

/**
* Moodle database: export and delete.
*
* @package tool_log
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

namespace tool_log\local\privacy;
defined('MOODLE_INTERNAL') || die();

use context;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\writer;

/**
* Moodle database: export and delete trait.
*
* This is to be used with logstores which use a database and table with the same columns
* as the core plugin 'logstore_standard'.
*
* This trait expects the following methods to be present in the object:
*
* - public static function get_database_and_table(): [moodle_database|null, string|null]
* - public static function get_export_subcontext(): []
*
* @package tool_log
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
trait moodle_database_export_and_delete {

/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist) {
list($db, $table) = static::get_database_and_table();
if (!$db || !$table) {
return;
}

$userid = $contextlist->get_user()->id;
list($insql, $inparams) = $db->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);

$sql = "(userid = :userid1 OR relateduserid = :userid2 OR realuserid = :userid3) AND contextid $insql";
$params = array_merge($inparams, [
'userid1' => $userid,
'userid2' => $userid,
'userid3' => $userid,
]);

$path = static::get_export_subcontext();
$flush = function($lastcontextid, $data) use ($path) {
$context = context::instance_by_id($lastcontextid);
writer::with_context($context)->export_data($path, (object) ['logs' => $data]);
};

$lastcontextid = null;
$data = [];
$recordset = $db->get_recordset_select($table, $sql, $params, 'contextid, timecreated, id');
foreach ($recordset as $record) {
if ($lastcontextid && $lastcontextid != $record->contextid) {
$flush($lastcontextid, $data);
$data = [];
}
$data[] = helper::transform_standard_log_record_for_userid($record, $userid);
$lastcontextid = $record->contextid;
}
if ($lastcontextid) {
$flush($lastcontextid, $data);
}
$recordset->close();
}

/**
* Delete all data for all users in the specified context.
*
* @param context $context The specific context to delete data for.
*/
public static function delete_data_for_all_users_in_context(context $context) {
list($db, $table) = static::get_database_and_table();
if (!$db || !$table) {
return;
}
$db->delete_records($table, ['contextid' => $context->id]);
}

/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
list($db, $table) = static::get_database_and_table();
if (!$db || !$table) {
return;
}
list($insql, $inparams) = $db->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
$params = array_merge($inparams, ['userid' => $contextlist->get_user()->id]);
$db->delete_records_select($table, "userid = :userid AND contextid $insql", $params);
}

}

0 comments on commit 8ff7363

Please sign in to comment.