. /** * Data provider. * * @package logstore_legacy * @copyright 2018 Frédéric Massart * @author Frédéric Massart * @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 * @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]; } }