You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
9.2 KiB
256 lines
9.2 KiB
2 years ago
|
<?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/>.
|
||
|
|
||
|
/**
|
||
|
* Data provider.
|
||
|
*
|
||
|
* @package logstore_legacy
|
||
|
* @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 logstore_legacy\privacy;
|
||
|
defined('MOODLE_INTERNAL') || die();
|
||
|
|
||
|
use context;
|
||
|
use core_privacy\local\metadata\collection;
|
||
|
use core_privacy\local\request\approved_contextlist;
|
||
|
use core_privacy\local\request\contextlist;
|
||
|
use core_privacy\local\request\transform;
|
||
|
use core_privacy\local\request\writer;
|
||
|
use tool_log\local\privacy\helper;
|
||
|
|
||
|
/**
|
||
|
* Data provider class.
|
||
|
*
|
||
|
* @package logstore_legacy
|
||
|
* @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 provider implements
|
||
|
\core_privacy\local\metadata\provider,
|
||
|
\tool_log\local\privacy\logstore_provider,
|
||
|
\tool_log\local\privacy\logstore_userlist_provider {
|
||
|
|
||
|
/**
|
||
|
* Returns metadata.
|
||
|
*
|
||
|
* @param collection $collection The initialised collection to add items to.
|
||
|
* @return collection A listing of user data stored through this system.
|
||
|
*/
|
||
|
public static function get_metadata(collection $collection) : collection {
|
||
|
$collection->add_external_location_link('log', [
|
||
|
'time' => 'privacy:metadata:log:time',
|
||
|
'userid' => 'privacy:metadata:log:userid',
|
||
|
'ip' => 'privacy:metadata:log:ip',
|
||
|
'action' => 'privacy:metadata:log:action',
|
||
|
'url' => 'privacy:metadata:log:url',
|
||
|
'info' => 'privacy:metadata:log:info',
|
||
|
], 'privacy:metadata:log');
|
||
|
return $collection;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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) {
|
||
|
$sql = "
|
||
|
SELECT ctx.id
|
||
|
FROM {context} ctx
|
||
|
JOIN {log} l
|
||
|
ON (l.cmid = 0 AND l.course = ctx.instanceid AND ctx.contextlevel = :courselevel)
|
||
|
OR (l.cmid > 0 AND l.cmid = ctx.instanceid AND ctx.contextlevel = :modulelevel)
|
||
|
OR (l.course <= 0 AND ctx.id = :syscontextid)
|
||
|
WHERE l.userid = :userid";
|
||
|
$params = [
|
||
|
'courselevel' => CONTEXT_COURSE,
|
||
|
'modulelevel' => CONTEXT_MODULE,
|
||
|
'syscontextid' => SYSCONTEXTID,
|
||
|
'userid' => $userid,
|
||
|
];
|
||
|
$contextlist->add_from_sql($sql, $params);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add user IDs that contain user information for the specified context.
|
||
|
*
|
||
|
* @param \core_privacy\local\request\userlist $userlist The userlist to add the users to.
|
||
|
* @return void
|
||
|
*/
|
||
|
public static function add_userids_for_context(\core_privacy\local\request\userlist $userlist) {
|
||
|
$context = $userlist->get_context();
|
||
|
list($insql, $params) = static::get_sql_where_from_contexts([$context]);
|
||
|
|
||
|
$sql = "SELECT l.userid
|
||
|
FROM {log} l
|
||
|
WHERE $insql";
|
||
|
$userlist->add_from_sql('userid', $sql, $params);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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) {
|
||
|
global $DB;
|
||
|
|
||
|
$userid = $contextlist->get_user()->id;
|
||
|
list($insql, $inparams) = static::get_sql_where_from_contexts($contextlist->get_contexts());
|
||
|
if (empty($insql)) {
|
||
|
return;
|
||
|
}
|
||
|
$sql = "userid = :userid AND $insql";
|
||
|
$params = array_merge($inparams, ['userid' => $userid]);
|
||
|
|
||
|
$path = [get_string('privacy:path:logs', 'tool_log'), get_string('pluginname', 'logstore_legacy')];
|
||
|
$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('log', $sql, $params, 'course, cmid, time, id');
|
||
|
foreach ($recordset as $record) {
|
||
|
$event = \logstore_legacy\event\legacy_logged::restore_legacy($record);
|
||
|
$context = $event->get_context();
|
||
|
if ($lastcontextid && $lastcontextid != $context->id) {
|
||
|
$flush($lastcontextid, $data);
|
||
|
$data = [];
|
||
|
}
|
||
|
|
||
|
$extra = $event->get_logextra();
|
||
|
$data[] = [
|
||
|
'name' => $event->get_name(),
|
||
|
'description' => $event->get_description(),
|
||
|
'timecreated' => transform::datetime($event->timecreated),
|
||
|
'ip' => $extra['ip'],
|
||
|
'origin' => helper::transform_origin($extra['origin']),
|
||
|
];
|
||
|
|
||
|
$lastcontextid = $context->id;
|
||
|
}
|
||
|
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) {
|
||
|
global $DB;
|
||
|
list($sql, $params) = static::get_sql_where_from_contexts([$context]);
|
||
|
if (empty($sql)) {
|
||
|
return;
|
||
|
}
|
||
|
$DB->delete_records_select('log', $sql, $params);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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) {
|
||
|
global $DB;
|
||
|
list($sql, $params) = static::get_sql_where_from_contexts($contextlist->get_contexts());
|
||
|
if (empty($sql)) {
|
||
|
return;
|
||
|
}
|
||
|
$userid = $contextlist->get_user()->id;
|
||
|
$DB->delete_records_select('log', "$sql AND userid = :userid", array_merge($params, ['userid' => $userid]));
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Delete all data for a list of users in the specified context.
|
||
|
*
|
||
|
* @param \core_privacy\local\request\approved_userlist $userlist The specific context and users to delete data for.
|
||
|
* @return void
|
||
|
*/
|
||
|
public static function delete_data_for_userlist(\core_privacy\local\request\approved_userlist $userlist) {
|
||
|
global $DB;
|
||
|
list($sql, $params) = static::get_sql_where_from_contexts([$userlist->get_context()]);
|
||
|
if (empty($sql)) {
|
||
|
return;
|
||
|
}
|
||
|
list($usersql, $userparams) = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED);
|
||
|
$params = array_merge($params, $userparams);
|
||
|
$DB->delete_records_select('log', "$sql AND userid $usersql", $params);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get an SQL where statement from a list of contexts.
|
||
|
*
|
||
|
* @param array $contexts The contexts.
|
||
|
* @return array [$sql, $params]
|
||
|
*/
|
||
|
protected static function get_sql_where_from_contexts(array $contexts) {
|
||
|
global $DB;
|
||
|
|
||
|
$sorted = array_reduce($contexts, function ($carry, $context) {
|
||
|
$level = $context->contextlevel;
|
||
|
if ($level == CONTEXT_MODULE || $level == CONTEXT_COURSE) {
|
||
|
$carry[$level][] = $context->instanceid;
|
||
|
} else if ($level == CONTEXT_SYSTEM) {
|
||
|
$carry[$level] = $context->id;
|
||
|
}
|
||
|
return $carry;
|
||
|
}, [
|
||
|
CONTEXT_COURSE => [],
|
||
|
CONTEXT_MODULE => [],
|
||
|
CONTEXT_SYSTEM => null,
|
||
|
]);
|
||
|
|
||
|
$sqls = [];
|
||
|
$params = [];
|
||
|
|
||
|
if (!empty($sorted[CONTEXT_MODULE])) {
|
||
|
list($insql, $inparams) = $DB->get_in_or_equal($sorted[CONTEXT_MODULE], SQL_PARAMS_NAMED);
|
||
|
$sqls[] = "cmid $insql";
|
||
|
$params = array_merge($params, $inparams);
|
||
|
}
|
||
|
|
||
|
if (!empty($sorted[CONTEXT_COURSE])) {
|
||
|
list($insql, $inparams) = $DB->get_in_or_equal($sorted[CONTEXT_COURSE], SQL_PARAMS_NAMED);
|
||
|
|
||
|
$sqls[] = "cmid = 0 AND course $insql";
|
||
|
$params = array_merge($params, $inparams);
|
||
|
}
|
||
|
|
||
|
if (!empty($sorted[CONTEXT_SYSTEM])) {
|
||
|
$sqls[] = "course <= 0";
|
||
|
}
|
||
|
|
||
|
if (empty($sqls)) {
|
||
|
return [null, null];
|
||
|
}
|
||
|
|
||
|
return ['((' . implode(') OR (', $sqls) . '))', $params];
|
||
|
}
|
||
|
}
|