AutorÃa | Ultima modificación | Ver Log |
<?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/>.
/**
* Contains class mod_zoom\privacy\provider
*
* @package mod_zoom
* @copyright 2018 UC Regents
* @author Kubilay Agi
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_zoom\privacy;
use context;
use context_module;
use core_privacy\local\metadata\collection;
use core_privacy\local\metadata\provider as metadata_provider;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\approved_userlist;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\core_userlist_provider;
use core_privacy\local\request\helper;
use core_privacy\local\request\plugin\provider as request_plugin_provider;
use core_privacy\local\request\transform;
use core_privacy\local\request\userlist;
use core_privacy\local\request\writer;
/**
* Ad hoc task that performs the actions for approved data privacy requests.
*/
class provider implements core_userlist_provider, metadata_provider, request_plugin_provider {
/**
* Returns meta data about this system.
*
* @param collection $coll The collection to add metadata to.
* @return collection The array of metadata
*/
public static function get_metadata(collection $coll): collection {
// Add all user data fields to the collection.
$coll->add_database_table('zoom_meeting_participants', [
'name' => 'privacy:metadata:zoom_meeting_participants:name',
'user_email' => 'privacy:metadata:zoom_meeting_participants:user_email',
'join_time' => 'privacy:metadata:zoom_meeting_participants:join_time',
'leave_time' => 'privacy:metadata:zoom_meeting_participants:leave_time',
'duration' => 'privacy:metadata:zoom_meeting_participants:duration',
], 'privacy:metadata:zoom_meeting_participants');
$coll->add_database_table(
'zoom_meeting_details',
['topic' => 'privacy:metadata:zoom_meeting_details:topic'],
'privacy:metadata:zoom_meeting_details'
);
$coll->add_database_table(
'zoom_meeting_recordings_view',
['userid' => 'privacy:metadata:zoom_meeting_view:userid'],
'privacy:metadata:zoom_meeting_view'
);
$coll->add_database_table(
'zoom_breakout_participants',
['userid' => 'privacy:metadata:zoom_breakout_participants:userid'],
'privacy:metadata:zoom_breakout_participants'
);
return $coll;
}
/**
* Get the list of contexts that contain user information for the specified user.
*
* @param int $userid The user to search.
* @return contextlist $contextlist The list of contexts used in this plugin.
*/
public static function get_contexts_for_userid(int $userid): contextlist {
// Query the database for context IDs give a specific user ID and return these to the user.
$contextlist = new contextlist();
$sql = 'SELECT c.id
FROM {context} c
INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname
INNER JOIN {zoom} z ON z.id = cm.instance
LEFT JOIN {zoom_meeting_details} zmd ON zmd.zoomid = z.id
LEFT JOIN {zoom_meeting_participants} zmp ON zmp.detailsid = zmd.id
LEFT JOIN {zoom_meeting_recordings} zmr ON zmr.zoomid = z.id
LEFT JOIN {zoom_meeting_recordings_view} zmrv ON zmrv.recordingsid = zmr.id
WHERE zmp.userid = :userid1 OR zmrv.userid = :userid2
';
$params = [
'modname' => 'zoom',
'contextlevel' => CONTEXT_MODULE,
'userid1' => $userid,
'userid2' => $userid,
];
$contextlist->add_from_sql($sql, $params);
return $contextlist;
}
/**
* Get the list of users who have data within a context.
*
* @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
*/
public static function get_users_in_context(userlist $userlist) {
$context = $userlist->get_context();
if (!($context instanceof context_module)) {
return;
}
$params = [
'instanceid' => $context->instanceid,
'modulename' => 'zoom',
];
$sql = "SELECT zmp.userid
FROM {zoom_meeting_participants} zmp
JOIN {zoom_meeting_details} zmd ON zmd.id = zmp.detailsid
JOIN {zoom} z ON zmd.zoomid = z.id
JOIN {modules} m ON m.name = :modulename
JOIN {course_modules} cm ON z.id = cm.instance AND m.id = cm.module
WHERE cm.id = :instanceid";
$userlist->add_from_sql('userid', $sql, $params);
$sql = "SELECT zmrv.userid
FROM {zoom_meeting_recordings_view} zmrv
JOIN {zoom_meeting_recordings} zmr ON zmr.id = zmrv.recordingsid
JOIN {zoom} z ON zmr.zoomid = z.id
JOIN {modules} m ON m.name = :modulename
JOIN {course_modules} cm ON z.id = cm.instance AND m.id = cm.module
WHERE cm.id = :instanceid";
$userlist->add_from_sql('userid', $sql, $params);
$sql = "SELECT zbp.userid
FROM {zoom_breakout_participants} zbp
JOIN {zoom_meeting_breakout_rooms} zmbr ON zbp.breakoutroomid = zmbr.id
JOIN {zoom} z ON zmbr.zoomid = z.id
JOIN {modules} m ON m.name = :modulename
JOIN {course_modules} cm ON z.id = cm.instance AND m.id = cm.module
WHERE cm.id = :instanceid";
$userlist->add_from_sql('userid', $sql, $params);
}
/**
* Export all user data for the specified user, in the specified contexts, using the supplied exporter instance.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
* @link http://tandl.churchward.ca/2018/06/implementing-moodles-privacy-api-in.html
*/
public static function export_user_data(approved_contextlist $contextlist) {
global $DB;
if (empty($contextlist->count())) {
return;
}
$user = $contextlist->get_user();
[$contextsql, $contextparams] = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
$sql = "SELECT zmp.id,
zmd.topic,
zmp.name,
zmp.user_email,
zmp.join_time,
zmp.leave_time,
zmp.duration,
cm.id AS cmid
FROM {context} c
INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname
INNER JOIN {zoom} z ON z.id = cm.instance
INNER JOIN {zoom_meeting_details} zmd ON zmd.zoomid = z.id
INNER JOIN {zoom_meeting_participants} zmp ON zmp.detailsid = zmd.id
WHERE c.id $contextsql
AND zmp.userid = :userid
ORDER BY cm.id ASC
";
$params = [
'modname' => 'zoom',
'contextlevel' => CONTEXT_MODULE,
'userid' => $user->id,
] + $contextparams;
$participantinstances = $DB->get_recordset_sql($sql, $params);
foreach ($participantinstances as $participantinstance) {
$context = context_module::instance($participantinstance->cmid);
$contextdata = helper::get_context_data($context, $user);
$instancedata = [
'topic' => $participantinstance->topic,
'participant_name' => $participantinstance->name,
'user_email' => $participantinstance->user_email,
'join_time' => transform::datetime($participantinstance->join_time),
'leave_time' => transform::datetime($participantinstance->leave_time),
'duration' => $participantinstance->duration,
];
$contextdata = (object) array_merge((array) $contextdata, $instancedata);
writer::with_context($context)->export_data([], $contextdata);
}
$participantinstances->close();
$sql = "SELECT zmrv.id,
zmr.name,
zmrv.userid,
zmrv.viewed,
zmrv.timemodified,
cm.id AS cmid
FROM {context} c
INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname
INNER JOIN {zoom} z ON z.id = cm.instance
INNER JOIN {zoom_meeting_recordings} zmr ON zmr.zoomid = z.id
INNER JOIN {zoom_meeting_recordings_view} zmrv ON zmrv.recordingsid = zmr.id
WHERE c.id $contextsql
AND zmrv.userid = :userid
ORDER BY cm.id ASC
";
$params = [
'modname' => 'zoom',
'contextlevel' => CONTEXT_MODULE,
'userid' => $user->id,
] + $contextparams;
$recordingviewinstances = $DB->get_recordset_sql($sql, $params);
foreach ($recordingviewinstances as $recordingviewinstance) {
$context = context_module::instance($recordingviewinstance->cmid);
$contextdata = helper::get_context_data($context, $user);
$instancedata = [
'recording_name' => $recordingviewinstance->name,
'userid' => $recordingviewinstance->userid,
'viewed' => $recordingviewinstance->viewed,
'timemodified' => transform::datetime($recordingviewinstance->timemodified),
];
$contextdata = (object) array_merge((array) $contextdata, $instancedata);
writer::with_context($context)->export_data([], $contextdata);
}
$recordingviewinstances->close();
}
/**
* Delete all personal data for all users in the specified context.
*
* @param context $context Context to delete data from.
*/
public static function delete_data_for_all_users_in_context(context $context) {
global $DB;
if (!($context instanceof context_module)) {
return;
}
// We delete each participant entry manually because deletes do not cascade.
if ($cm = get_coursemodule_from_id('zoom', $context->instanceid)) {
$meetingdetails = $DB->get_records('zoom_meeting_details', ['zoomid' => $cm->instance]);
foreach ($meetingdetails as $meetingdetail) {
$DB->delete_records('zoom_meeting_participants', ['detailsid' => $meetingdetail->id]);
}
$DB->delete_records('zoom_meeting_details', ['zoomid' => $cm->instance]);
$meetingrecordings = $DB->get_records('zoom_meeting_recordings', ['zoomid' => $cm->instance]);
foreach ($meetingrecordings as $recording) {
$DB->delete_records('zoom_meeting_recordings_view', ['recordingsid' => $recording->id]);
}
$DB->delete_records('zoom_meeting_recordings', ['zoomid' => $cm->instance]);
$breakoutrooms = $DB->get_records('zoom_meeting_breakout_rooms', ['zoomid' => $cm->instance]);
foreach ($breakoutrooms as $room) {
$DB->delete_records('zoom_breakout_participants', ['breakoutroomid' => $room->id]);
}
$DB->delete_records('zoom_meeting_breakout_rooms', ['zoomid' => $cm->instance]);
}
}
/**
* 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;
if (empty($contextlist->count())) {
return;
}
$user = $contextlist->get_user();
foreach ($contextlist->get_contexts() as $context) {
if (!($context instanceof context_module)) {
continue;
}
if ($cm = get_coursemodule_from_id('zoom', $context->instanceid)) {
$meetingdetails = $DB->get_records('zoom_meeting_details', ['zoomid' => $cm->instance]);
foreach ($meetingdetails as $meetingdetail) {
$DB->delete_records('zoom_meeting_participants', ['detailsid' => $meetingdetail->id, 'userid' => $user->id]);
}
$meetingrecordings = $DB->get_records('zoom_meeting_recordings', ['zoomid' => $cm->instance]);
foreach ($meetingrecordings as $recording) {
$DB->delete_records('zoom_meeting_recordings_view', ['recordingsid' => $recording->id, 'userid' => $user->id]);
}
$breakoutrooms = $DB->get_records('zoom_meeting_breakout_rooms', ['zoomid' => $cm->instance]);
foreach ($breakoutrooms as $room) {
$DB->delete_records('zoom_breakout_participants', ['breakoutroomid' => $room->id, 'userid' => $user->id]);
}
}
}
}
/**
* Delete multiple users within a single context.
*
* @param approved_userlist $userlist The approved context and user information to delete information for.
*/
public static function delete_data_for_users(approved_userlist $userlist) {
global $DB;
$context = $userlist->get_context();
if (!($context instanceof context_module)) {
return;
}
// Prepare SQL to gather all completed IDs.
$userids = $userlist->get_userids();
[$insql, $inparams] = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
$params = array_merge($inparams, ['contextid' => $context->id, 'modlevel' => CONTEXT_MODULE]);
$sql = "SELECT zmd.id
FROM {zoom_meeting_details} zmd
JOIN {zoom} z ON zmd.zoomid = z.id
JOIN {modules} m ON m.name = 'zoom'
JOIN {course_modules} cm ON z.id = cm.instance AND m.id = cm.module
JOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :modlevel
WHERE ctx.id = :contextid";
$DB->delete_records_select('zoom_meeting_participants', "userid $insql AND detailsid IN ($sql)", $params);
$sql = "SELECT zmr.id
FROM {zoom_meeting_recordings} zmr
JOIN {zoom} z ON zmr.zoomid = z.id
JOIN {modules} m ON m.name = 'zoom'
JOIN {course_modules} cm ON z.id = cm.instance AND m.id = cm.module
JOIN {context} ctx ON cm.id = ctx.instanceid AND ctx.contextlevel = :modlevel
WHERE ctx.id = :contextid";
$DB->delete_records_select('zoom_meeting_recordings_view', "userid $insql AND recordingsid IN ($sql)", $params);
$sql = "SELECT zmbr.id
FROM {zoom_meeting_breakout_rooms} zmbr
JOIN {zoom} z ON zmbr.zoomid = z.id
JOIN {modules} m ON m.name = 'zoom'
JOIN {course_modules} cm ON z.id = cm.instance AND m.id = cm.module
JOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :modlevel
WHERE ctx.id = :contextid";
$DB->delete_records_select('zoom_breakout_participants', "userid $insql AND breakoutroomid IN ($sql)", $params);
}
}