Export all user data for the specified user, in the specified contexts.

@param approved_contextlist $contextlist The approved contexts to export information for.
765874
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        if (empty($contextlist->count())) {
            return;
        }

        $user = $contextlist->get_user();

        list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);

        // Values of ep.receiver_email and ep.business are already normalised to lowercase characters by PayPal,
        // therefore there is no need to use LOWER() on them in the following query.
        $sql = "SELECT ep.*
                  FROM {enrol_paypal} ep
                  JOIN {enrol} e ON ep.instanceid = e.id
                  JOIN {context} ctx ON e.courseid = ctx.instanceid AND ctx.contextlevel = :contextcourse
                  JOIN {user} u ON u.id = ep.userid OR LOWER(u.email) = ep.receiver_email OR LOWER(u.email) = ep.business
                 WHERE ctx.id {$contextsql} AND u.id = :userid
              ORDER BY e.courseid";

        $params = [
            'contextcourse' => CONTEXT_COURSE,
            'userid'        => $user->id,
            'emailuserid'   => $user->id,
        ];
        $params += $contextparams;

        // Reference to the course seen in the last iteration of the loop. By comparing this with the current record, and
        // because we know the results are ordered, we know when we've moved to the PayPal transactions for a new course
        // and therefore when we can export the complete data for the last course.
        $lastcourseid = null;

        $strtransactions = get_string('transactions', 'enrol_paypal');
        $transactions = [];
        $paypalrecords = $DB->get_recordset_sql($sql, $params);
        foreach ($paypalrecords as $paypalrecord) {
            if ($lastcourseid != $paypalrecord->courseid) {
                if (!empty($transactions)) {
                    $coursecontext = \context_course::instance($paypalrecord->courseid);
                    writer::with_context($coursecontext)->export_data(
                            [$strtransactions],
                            (object) ['transactions' => $transactions]
                    );
                }
                $transactions = [];
            }

            $transaction = (object) [
                'receiver_id'         => $paypalrecord->receiver_id,
                'item_name'           => $paypalrecord->item_name,
                'userid'              => $paypalrecord->userid,
                'memo'                => $paypalrecord->memo,
                'tax'                 => $paypalrecord->tax,
                'option_name1'        => $paypalrecord->option_name1,
                'option_selection1_x' => $paypalrecord->option_selection1_x,
                'option_name2'        => $paypalrecord->option_name2,
                'option_selection2_x' => $paypalrecord->option_selection2_x,
                'payment_status'      => $paypalrecord->payment_status,
                'pending_reason'      => $paypalrecord->pending_reason,
                'reason_code'         => $paypalrecord->reason_code,
                'txn_id'              => $paypalrecord->txn_id,
                'parent_txn_id'       => $paypalrecord->parent_txn_id,
                'payment_type'        => $paypalrecord->payment_type,
                'timeupdated'         => \core_privacy\local\request\transform::datetime($paypalrecord->timeupdated),
            ];
            if ($paypalrecord->userid == $user->id) {
                $transaction->userid = $paypalrecord->userid;
            }
            if ($paypalrecord->business == \core_text::strtolower($user->email)) {
                $transaction->business = $paypalrecord->business;
            }
            if ($paypalrecord->receiver_email == \core_text::strtolower($user->email)) {
                $transaction->receiver_email = $paypalrecord->receiver_email;
            }

            $transactions[] = $paypalrecord;

            $lastcourseid = $paypalrecord->courseid;
        }
        $paypalrecords->close();

        // The data for the last activity won't have been written yet, so make sure to write it now!
        if (!empty($transactions)) {
            $coursecontext = \context_course::instance($paypalrecord->courseid);
            writer::with_context($coursecontext)->export_data(
                    [$strtransactions],
                    (object) ['transactions' => $transactions]
            );
        }
    }
1160678
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        if (empty($contextlist->count())) {
            return;
        }

        $user = $contextlist->get_user();

        list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);

        $sql = "SELECT cm.id AS cmid,
                       co.text as answer,
                       ca.timemodified
                  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 {choice} ch ON ch.id = cm.instance
            INNER JOIN {choice_options} co ON co.choiceid = ch.id
            INNER JOIN {choice_answers} ca ON ca.optionid = co.id AND ca.choiceid = ch.id
                 WHERE c.id {$contextsql}
                       AND ca.userid = :userid
              ORDER BY cm.id";

        $params = ['modname' => 'choice', 'contextlevel' => CONTEXT_MODULE, 'userid' => $user->id] + $contextparams;

        // Reference to the choice activity seen in the last iteration of the loop. By comparing this with the current record, and
        // because we know the results are ordered, we know when we've moved to the answers for a new choice activity and therefore
        // when we can export the complete data for the last activity.
        $lastcmid = null;

        $choiceanswers = $DB->get_recordset_sql($sql, $params);
        foreach ($choiceanswers as $choiceanswer) {
            // If we've moved to a new choice, then write the last choice data and reinit the choice data array.
            if ($lastcmid != $choiceanswer->cmid) {
                if (!empty($choicedata)) {
                    $context = \context_module::instance($lastcmid);
                    self::export_choice_data_for_user($choicedata, $context, $user);
                }
                $choicedata = [
                    'answer' => [],
                    'timemodified' => \core_privacy\local\request\transform::datetime($choiceanswer->timemodified),
                ];
            }
            $choicedata['answer'][] = $choiceanswer->answer;
            $lastcmid = $choiceanswer->cmid;
        }
        $choiceanswers->close();

        // The data for the last activity won't have been written yet, so make sure to write it now!
        if (!empty($choicedata)) {
            $context = \context_module::instance($lastcmid);
            self::export_choice_data_for_user($choicedata, $context, $user);
        }
    }
139260
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        $user = $contextlist->get_user();

        // Firstly export all autosave records from all contexts in the list owned by the given user.

        list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
        $contextparams['userid'] = $user->id;

        $sql = "SELECT *
                  FROM {editor_atto_autosave}
                 WHERE userid = :userid AND contextid {$contextsql}";

        $autosaves = $DB->get_recordset_sql($sql, $contextparams);
        self::export_autosaves($user, $autosaves);

        // Additionally export all eventual records in the given user's context regardless the actual owner.
        // We still consider them to be the user's personal data even when edited by someone else.

        list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
        $contextparams['userid'] = $user->id;
        $contextparams['contextuser'] = CONTEXT_USER;

        $sql = "SELECT eas.*
                  FROM {editor_atto_autosave} eas
                  JOIN {context} c ON c.id = eas.contextid
                 WHERE c.id {$contextsql} AND c.contextlevel = :contextuser AND c.instanceid = :userid";

        $autosaves = $DB->get_recordset_sql($sql, $contextparams);
        self::export_autosaves($user, $autosaves);
    }
445606
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        $context = \context_user::instance($contextlist->get_user()->id);

        $sql = "SELECT ml.id, mh.wwwroot, mh.name, ml.remoteid, ml.time, ml.userid, ml.ip, ml.course,
                       ml.coursename, ml.module, ml.cmid, ml.action, ml.url, ml.info
                  FROM {mnet_log} ml
                  JOIN {mnet_host} mh ON mh.id = ml.hostid
                 WHERE ml.userid = :userid
              ORDER BY mh.name, ml.coursename";
        $params = ['userid' => $contextlist->get_user()->id];

        $data = [];
        $lastcourseid = null;

        $logentries = $DB->get_recordset_sql($sql, $params);
        foreach ($logentries as $logentry) {
            $item = (object) [
                    'time' => transform::datetime($logentry->time),
                    'remoteid' => $logentry->remoteid,
                    'ip' => $logentry->ip,
                    'course' => $logentry->course,
                    'coursename' => format_string($logentry->coursename),
                    'module' => $logentry->module,
                    'cmid' => $logentry->cmid,
                    'action' => $logentry->action,
                    'url' => $logentry->url,
                    'info' => format_string($logentry->info)
            ];

            $item->externalhost =
                    ($logentry->name == '') ? preg_replace('#^https?://#', '', $logentry->wwwroot) :
                            preg_replace('#^https?://#', '', $logentry->name);

            if ($lastcourseid && $lastcourseid != $logentry->course) {
                $path = [get_string('pluginname', 'auth_mnet'), $data[0]->externalhost, $data[0]->coursename];
                writer::with_context($context)->export_data($path, (object) $data);
                $data = [];
            }

            $data[] = $item;
            $lastcourseid = $logentry->course;
        }
        $logentries->close();

        $path = [get_string('pluginname', 'auth_mnet'), $item->externalhost, $item->coursename];
        writer::with_context($context)->export_data($path, (object) $data);
    }
151616
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        // Remove contexts different from COURSE_MODULE.
        $contexts = array_reduce($contextlist->get_contexts(), function($carry, $context) {
            if ($context->contextlevel == CONTEXT_MODULE) {
                $carry[] = $context->id;
            }
            return $carry;
        }, []);

        if (empty($contexts)) {
            return;
        }

        $user = $contextlist->get_user();
        $userid = $user->id;
        // Get SCORM data.
        foreach ($contexts as $contextid) {
            $context = \context::instance_by_id($contextid);
            $data = helper::get_context_data($context, $user);
            writer::with_context($context)->export_data([], $data);
            helper::export_context_files($context, $user);
        }

        // Get scoes_track data.
        list($insql, $inparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
        $sql = "SELECT ss.id,
                       ss.attempt,
                       ss.element,
                       ss.value,
                       ss.timemodified,
                       ctx.id as contextid
                  FROM {scorm_scoes_track} ss
                  JOIN {course_modules} cm
                    ON cm.instance = ss.scormid
                  JOIN {context} ctx
                    ON ctx.instanceid = cm.id
                 WHERE ctx.id $insql
                   AND ss.userid = :userid";
        $params = array_merge($inparams, ['userid' => $userid]);

        $alldata = [];
        $scoestracks = $DB->get_recordset_sql($sql, $params);
        foreach ($scoestracks as $track) {
            $alldata[$track->contextid][$track->attempt][] = (object)[
                    'element' => $track->element,
                    'value' => $track->value,
                    'timemodified' => transform::datetime($track->timemodified),
                ];
        }
        $scoestracks->close();

        // The scoes_track data is organised in: {Course name}/{SCORM activity name}/{My attempts}/{Attempt X}/data.json
        // where X is the attempt number.
        array_walk($alldata, function($attemptsdata, $contextid) {
            $context = \context::instance_by_id($contextid);
            array_walk($attemptsdata, function($data, $attempt) use ($context) {
                $subcontext = [
                    get_string('myattempts', 'scorm'),
                    get_string('attempt', 'scorm'). " $attempt"
                ];
                writer::with_context($context)->export_data(
                    $subcontext,
                    (object)['scoestrack' => $data]
                );
            });
        });

        // Get aicc_session data.
        $sql = "SELECT ss.id,
                       ss.scormmode,
                       ss.scormstatus,
                       ss.attempt,
                       ss.lessonstatus,
                       ss.sessiontime,
                       ss.timecreated,
                       ss.timemodified,
                       ctx.id as contextid
                  FROM {scorm_aicc_session} ss
                  JOIN {course_modules} cm
                    ON cm.instance = ss.scormid
                  JOIN {context} ctx
                    ON ctx.instanceid = cm.id
                 WHERE ctx.id $insql
                   AND ss.userid = :userid";
        $params = array_merge($inparams, ['userid' => $userid]);

        $alldata = [];
        $aiccsessions = $DB->get_recordset_sql($sql, $params);
        foreach ($aiccsessions as $aiccsession) {
            $alldata[$aiccsession->contextid][] = (object)[
                    'scormmode' => $aiccsession->scormmode,
                    'scormstatus' => $aiccsession->scormstatus,
                    'lessonstatus' => $aiccsession->lessonstatus,
                    'attempt' => $aiccsession->attempt,
                    'sessiontime' => $aiccsession->sessiontime,
                    'timecreated' => transform::datetime($aiccsession->timecreated),
                    'timemodified' => transform::datetime($aiccsession->timemodified),
                ];
        }
        $aiccsessions->close();

        // The aicc_session data is organised in: {Course name}/{SCORM activity name}/{My AICC sessions}/data.json
        // In this case, the attempt hasn't been included in the json file because it can be null.
        array_walk($alldata, function($data, $contextid) {
            $context = \context::instance_by_id($contextid);
            $subcontext = [
                get_string('myaiccsessions', 'scorm')
            ];
            writer::with_context($context)->export_data(
                $subcontext,
                (object)['sessions' => $data]
            );
        });
    }
1341424
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        if (empty($contextlist)) {
             return;
        }

        $rolesnames = self::get_roles_name();
        $userid = $contextlist->get_user()->id;
        $ctxfields = \context_helper::get_preload_record_columns_sql('ctx');
        list($insql, $inparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);

        // Role Assignments export data.
        $contexts = [
            CONTEXT_SYSTEM,
            CONTEXT_USER,
            CONTEXT_COURSECAT,
            CONTEXT_COURSE,
            CONTEXT_MODULE,
            CONTEXT_BLOCK
        ];
        list($inctxsql, $ctxparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
        $sql = "SELECT ra.id, ra.contextid, ra.roleid, ra.userid, ra.timemodified, ra.modifierid, $ctxfields
                  FROM {role_assignments} ra
                  JOIN {context} ctx
                    ON ctx.id = ra.contextid
                   AND ctx.contextlevel {$inctxsql}
                   AND (ra.userid = :userid OR ra.modifierid = :modifierid)
                   AND ra.component != 'tool_cohortroles'
                  JOIN {role} r
                    ON r.id = ra.roleid
                 WHERE ctx.id {$insql}";
        $params = ['userid' => $userid, 'modifierid' => $userid];
        $params += $inparams;
        $params += $ctxparams;
        $assignments = $DB->get_recordset_sql($sql, $params);
        foreach ($assignments as $assignment) {
            \context_helper::preload_from_record($assignment);
            $alldata[$assignment->contextid][$rolesnames[$assignment->roleid]][] = (object)[
                'timemodified' => transform::datetime($assignment->timemodified),
                'userid' => transform::user($assignment->userid),
                'modifierid' => transform::user($assignment->modifierid)
            ];
        }
        $assignments->close();
        if (!empty($alldata)) {
            array_walk($alldata, function($roledata, $contextid) {
                $context = \context::instance_by_id($contextid);
                array_walk($roledata, function($data, $rolename) use ($context) {
                    writer::with_context($context)->export_data(
                            [get_string('privacy:metadata:role_assignments', 'core_role'), $rolename],
                            (object)$data);
                });
            });
            unset($alldata);
        }

        // Role Capabilities export data.
        $strpermissions = self::get_permissions_name();
        $contexts = [
            CONTEXT_SYSTEM,
            CONTEXT_USER,
            CONTEXT_COURSECAT,
            CONTEXT_COURSE,
            CONTEXT_MODULE,
            CONTEXT_BLOCK
        ];
        list($inctxsql, $ctxparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
        $sql = "SELECT rc.id, rc.contextid, rc.capability, rc.permission, rc.timemodified, rc.roleid, $ctxfields
                  FROM {context} ctx
                  JOIN {role_capabilities} rc
                    ON rc.contextid = ctx.id
                   AND ((ctx.contextlevel {$inctxsql} AND rc.modifierid = :modifierid)
                    OR (ctx.contextlevel = :contextlevel AND ctx.instanceid = :userid))
                 WHERE ctx.id {$insql}";
        $params = [
            'modifierid' => $userid,
            'contextlevel' => CONTEXT_USER,
            'userid' => $userid
         ];
        $params += $inparams;
        $params += $ctxparams;
        $capabilities = $DB->get_recordset_sql($sql, $params);
        foreach ($capabilities as $capability) {
            \context_helper::preload_from_record($capability);
            $alldata[$capability->contextid][$rolesnames[$capability->roleid]][] = (object)[
                'timemodified' => transform::datetime($capability->timemodified),
                'capability' => $capability->capability,
                'permission' => $strpermissions[$capability->permission]
            ];
        }
        $capabilities->close();
        if (!empty($alldata)) {
            array_walk($alldata, function($capdata, $contextid) {
                $context = \context::instance_by_id($contextid);
                array_walk($capdata, function($data, $rolename) use ($context) {
                    writer::with_context($context)->export_data(
                            [get_string('privacy:metadata:role_capabilities', 'core_role'), $rolename],
                            (object)$data);
                });
            });
        }
    }
834683
public static function export_user_data(approved_contextlist $contextlist) {
        $user = $contextlist->get_user();
        foreach ($contextlist->get_contexts() as $context) {
            // Check if the context is a user context.
            if ($context->contextlevel == CONTEXT_USER && $context->instanceid == $user->id) {
                $results = static::get_records($user->id);
                foreach ($results as $result) {
                    $data = (object) [
                        'name' => $result->name,
                        'description' => $result->description,
                        'data' => transform::date($result->data)
                    ];
                    \core_privacy\local\request\writer::with_context($context)->export_data([
                        get_string('pluginname', 'profilefield_datetime')], $data);
                }
            }
        }
    }
992262
protected static function export_user_calendar_event_data(approved_contextlist $contextlist) {
        // Calendar Events can exist at Site, Course Category, Course, Course Group, User, or Course Modules contexts.
        $eventdetails = self::get_calendar_event_details_by_contextlist($contextlist);

        // Multiple Calendar Events of the same eventtype and time can exist for a context, so collate them for export.
        $eventrecords = [];
        foreach ($eventdetails as $eventdetail) {
            // Create an array key based on the contextid, eventtype, and time.
            $key = $eventdetail->contextid . $eventdetail->eventtype . $eventdetail->timestart;

            if (array_key_exists($key, $eventrecords) === false) {
                $eventrecords[$key] = [ $eventdetail ];
            } else {
                $eventrecords[$key] = array_merge($eventrecords[$key], [$eventdetail]);
            }
        }
        $eventdetails->close();

        // Export Calendar Event data.
        foreach ($eventrecords as $eventrecord) {
            $index = (count($eventrecord) > 1) ? 1 : 0;

            foreach ($eventrecord as $event) {
                // Export the events using the structure Calendar/Events/{datetime}/{eventtype}-event.json.
                $subcontexts = [
                    get_string('calendar', 'calendar'),
                    get_string('events', 'calendar'),
                    date('c', $event->timestart)
                ];
                $name = $event->eventtype . '-event';

                // Use name {eventtype}-event-{index}.json if multiple eventtypes and time exists at the same context.
                if ($index != 0) {
                    $name .= '-' . $index;
                    $index++;
                }

                $eventdetails = (object) [
                    'name' => $event->name,
                    'description' => $event->description,
                    'location' => $event->location,
                    'eventtype' => $event->eventtype,
                    'timestart' => transform::datetime($event->timestart),
                    'timeduration' => $event->timeduration
                ];

                $context = \context::instance_by_id($event->contextid);
                writer::with_context($context)->export_related_data($subcontexts, $name, $eventdetails);
            }
        }
    }
606047
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        $user = $contextlist->get_user();
        $userid = $user->id;
        $cmids = array_reduce($contextlist->get_contexts(), function($carry, $context) {
            if ($context->contextlevel == CONTEXT_MODULE) {
                $carry[] = $context->instanceid;
            }
            return $carry;
        }, []);
        if (empty($cmids)) {
            return;
        }

        $chatidstocmids = static::get_chat_ids_to_cmids_from_cmids($cmids);
        $chatids = array_keys($chatidstocmids);

        // Export the messages.
        list($insql, $inparams) = $DB->get_in_or_equal($chatids, SQL_PARAMS_NAMED);
        $params = array_merge($inparams, ['userid' => $userid]);
        $recordset = $DB->get_recordset_select('chat_messages', "chatid $insql AND userid = :userid", $params, 'timestamp, id');
        static::recordset_loop_and_export($recordset, 'chatid', [], function($carry, $record) use ($user, $chatidstocmids) {
            $message = $record->message;
            if ($record->issystem) {
                $message = get_string('message' . $record->message, 'mod_chat', fullname($user));
            }
            $carry[] = [
                'message' => $message,
                'sent_at' => transform::datetime($record->timestamp),
                'is_system_generated' => transform::yesno($record->issystem),
            ];
            return $carry;

        }, function($chatid, $data) use ($user, $chatidstocmids) {
            $context = context_module::instance($chatidstocmids[$chatid]);
            $contextdata = helper::get_context_data($context, $user);
            $finaldata = (object) array_merge((array) $contextdata, ['messages' => $data]);
            helper::export_context_files($context, $user);
            writer::with_context($context)->export_data([], $finaldata);
        });
    }
275090
protected static function export_user_data_lti_tool_proxies(approved_contextlist $contextlist) {
        global $DB;

        // Filter out any contexts that are not related to system context.
        $systemcontexts = array_filter($contextlist->get_contexts(), function($context) {
            return $context->contextlevel == CONTEXT_SYSTEM;
        });

        if (empty($systemcontexts)) {
            return;
        }

        $user = $contextlist->get_user();

        $systemcontext = \context_system::instance();

        $data = [];
        $ltiproxies = $DB->get_recordset('lti_tool_proxies', ['createdby' => $user->id], 'timecreated ASC');
        foreach ($ltiproxies as $ltiproxy) {
            $data[] = [
                'name' => format_string($ltiproxy->name, true, $systemcontext),
                'createdby' => transform::user($ltiproxy->createdby),
                'timecreated' => transform::datetime($ltiproxy->timecreated),
                'timemodified' => transform::datetime($ltiproxy->timemodified)
            ];
        }
        $ltiproxies->close();

        $finaldata = (object) ['lti_tool_proxies' => $data];
        writer::with_context($systemcontext)->export_data([], $finaldata);
    }
418589
public static function delete_data_for_user(approved_contextlist $contextlist) {
        foreach ($contextlist as $context) {
            // Let's be super certain that we have the right information for this user here.
            if ($context->contextlevel == CONTEXT_USER && $contextlist->get_user()->id == $context->instanceid) {
                static::delete_user_data($contextlist->get_user()->id, $contextlist->current());
            }
        }
    }
534103
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        // Ensure all contexts are CONTEXT_COURSE.
        $contexts = static::validate_contextlist_contexts($contextlist);
        if (empty($contexts)) {
            return;
        }

        // Get the context instance ids from the contexts. These  are the course ids..
        $contextinstanceids = array_map(function($context) {
            return $context->instanceid;
        }, $contexts);
        $userid = $contextlist->get_user()->id;

        // Now, we just need to fetch and format all entries corresponding to the contextids provided.
        $sql = "SELECT ef.action, r.shortname, ef.courseid, ef.timestart, ef.timeend, ef.timemodified
                  FROM {enrol_flatfile} ef
                  JOIN {context} c ON c.contextlevel = :contextlevel AND c.instanceid = ef.courseid
                  JOIN {role} r ON r.id = ef.roleid
                 WHERE ef.userid = :userid";
        $params = ['contextlevel' => CONTEXT_COURSE, 'userid' => $userid];
        list($insql, $inparams) = $DB->get_in_or_equal($contextinstanceids, SQL_PARAMS_NAMED);
        $sql .= " AND ef.courseid $insql";
        $params = array_merge($params, $inparams);

        $futureenrolments = $DB->get_recordset_sql($sql, $params);
        $enrolmentdata = [];
        foreach ($futureenrolments as $futureenrolment) {
            // It's possible to have more than one future enrolment per course.
            $futureenrolment->timestart = transform::datetime($futureenrolment->timestart);
            $futureenrolment->timeend = transform::datetime($futureenrolment->timeend);
            $futureenrolment->timemodified = transform::datetime($futureenrolment->timemodified);
            $enrolmentdata[$futureenrolment->courseid][] = $futureenrolment;
        }
        $futureenrolments->close();

        // And finally, write out the data to the relevant course contexts.
        $subcontext = \core_enrol\privacy\provider::get_subcontext([get_string('pluginname', 'enrol_flatfile')]);
        foreach ($enrolmentdata as $courseid => $enrolments) {
            $data = (object) [
                'pendingenrolments' => $enrolments,
            ];
            writer::with_context(\context_course::instance($courseid))->export_data($subcontext, $data);
        }
    }
1274022
public static function export_user_data(approved_contextlist $contextlist) {
        if (empty($contextlist)) {
            return;
        }
        foreach ($contextlist as $context) {
            if ($context->contextlevel == CONTEXT_COURSE) {
                \core_group\privacy\provider::export_groups(
                    $context,
                    'enrol_meta',
                    [get_string('pluginname', 'enrol_meta')]
                );
            }
        }
    }
404381
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        if (empty($contextlist->count())) {
            return;
        }

        $user = $contextlist->get_user();

        list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);

        $sql = "SELECT ltiusers.lastgrade, ltiusers.lastaccess, ltiusers.timecreated, ltitools.contextid
                  FROM {enrol_lti_users} ltiusers
                  JOIN {enrol_lti_tools} ltitools
                    ON ltiusers.toolid = ltitools.id
                  JOIN {context} ctx
                    ON ctx.id = ltitools.contextid
                 WHERE ctx.id {$contextsql}
                   AND ltiusers.userid = :userid";
        $params = $contextparams + ['userid' => $user->id];
        $ltiusers = $DB->get_recordset_sql($sql, $params);
        self::recordset_loop_and_export($ltiusers, 'contextid', [], function($carry, $record) {
            $carry[] = [
                'lastgrade' => $record->lastgrade,
                'timecreated' => transform::datetime($record->lastaccess),
                'timemodified' => transform::datetime($record->timecreated)
            ];
            return $carry;
        }, function($contextid, $data) {
            $context = \context::instance_by_id($contextid);
            $finaldata = (object) $data;
            writer::with_context($context)->export_data(['enrol_lti_users'], $finaldata);
        });
    }
640107
public static function delete_data_for_user(approved_contextlist $contextlist) {
        if ($contextlist->get_component() != 'report_stats') {
            return;
        }
        foreach ($contextlist->get_contexts() as $context) {
            if ($context->contextlevel == CONTEXT_COURSE) {
                static::delete_stats($context->instanceid, $contextlist->get_user()->id);
            }
        }
    }
544950
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        foreach ($contextlist as $context) {
            if ($context->contextlevel != CONTEXT_MODULE) {
                continue;
            }
            $user = $contextlist->get_user();

            $rs = $DB->get_recordset_sql('SELECT w.wikimode, s.id AS subwikiid,
                    s.groupid AS subwikigroupid, s.userid AS subwikiuserid,
                    p.id AS pageid, p.userid AS pageuserid, p.title, p.cachedcontent, p.timecreated AS pagetimecreated,
                    p.timemodified AS pagetimemodified, p.timerendered AS pagetimerendered, p.pageviews, p.readonly,
                    v.id AS versionid, v.content, v.contentformat, v.version, v.timecreated AS versiontimecreated,
                    l.id AS lockid, l.sectionname, l.lockedat
                FROM {course_modules} cm
                JOIN {wiki} w ON w.id = cm.instance
                JOIN {wiki_subwikis} s ON cm.instance = s.wikiid
                LEFT JOIN {wiki_pages} p ON p.subwikiid = s.id
                LEFT JOIN {wiki_versions} v ON v.pageid = p.id AND v.userid = :user4
                LEFT JOIN {wiki_locks} l ON l.pageid = p.id AND l.userid = :user5
                WHERE cm.id = :cmid AND (s.userid = :user1 OR p.userid = :user2 OR v.userid = :user3 OR l.userid = :user6 OR
                     EXISTS (SELECT 1 FROM {comments} com WHERE com.itemid = p.id AND com.commentarea = :commentarea
                          AND com.contextid = :ctxid AND com.userid = :user7)
                )
                ORDER BY s.id, p.id, v.id',
                ['cmid' => $context->instanceid,
                    'user1' => $user->id, 'user2' => $user->id, 'user3' => $user->id, 'user4' => $user->id,
                    'user5' => $user->id, 'user6' => $user->id, 'user7' => $user->id, 'commentarea' => 'wiki_page',
                    'ctxid' => $context->id]);

            if (!$rs->current()) {
                $rs->close();
                continue;
            }

            $subwiki = [];
            $wikimode = null;
            foreach ($rs as $record) {
                if ($wikimode === null) {
                    $wikimode = $record->wikimode;
                }
                if (!isset($subwiki[$record->subwikiid])) {
                    self::export_subwiki($user, $context, $subwiki, $wikimode);
                    $subwiki = [$record->subwikiid => [
                        'groupid' => $record->subwikigroupid,
                        'userid' => $record->subwikiuserid ? transform::user($record->subwikiuserid) : 0,
                        'pages' => []
                    ]];
                }

                if (!$record->pageid) {
                    // This is an empty individual wiki.
                    continue;
                }

                // Prepend page title with the page id to guarantee uniqueness.
                $pagetitle = format_string($record->title, true, ['context' => $context]);
                $page = $record->pageid . ' ' . $pagetitle;
                if (!isset($subwiki[$record->subwikiid]['pages'][$page])) {
                    // Export basic details about the page.
                    $subwiki[$record->subwikiid]['pages'][$page] = ['page' => [
                        'id' => $record->pageid,
                        'title' => $pagetitle,
                        'cachedcontent' => $record->cachedcontent,
                    ]];
                    if ($record->pageuserid == $user->id) {
                        // This page belongs to this user. Export all details.
                        $subwiki[$record->subwikiid]['pages'][$page]['page'] += [
                            'userid' => transform::user($user->id),
                            'timecreated' => transform::datetime($record->pagetimecreated),
                            'timemodified' => transform::datetime($record->pagetimemodified),
                            'timerendered' => transform::datetime($record->pagetimerendered),
                            'pageviews' => $record->pageviews,
                            'readonly' => $record->readonly,
                        ];

                        $subwiki[$record->subwikiid]['pages'][$page]['page']['userid'] = transform::user($user->id);
                    }
                }

                if ($record->versionid) {
                    $subwiki[$record->subwikiid]['pages'][$page]['revisions'][$record->versionid] = [
                        'content' => $record->content,
                        'contentformat' => $record->contentformat,
                        'version' => $record->version,
                        'timecreated' => transform::datetime($record->versiontimecreated)
                    ];
                }

                if ($record->lockid) {
                    $subwiki[$record->subwikiid]['pages'][$page]['locks'][$record->lockid] = [
                        'sectionname' => $record->sectionname,
                        'lockedat' => transform::datetime($record->lockedat),
                    ];
                }

            }
            self::export_subwiki($user, $context, $subwiki, $wikimode);

            if ($subwiki) {
                // Export wiki itself.
                $contextdata = helper::get_context_data($context, $user);
                helper::export_context_files($context, $user);
                writer::with_context($context)->export_data([], $contextdata);
            }

            $rs->close();
        }
    }
1242757
public static function export_user_data(approved_contextlist $contextlist) {
        if (empty($contextlist->count())) {
            return;
        }

        $user = $contextlist->get_user();
        $datarequests = api::get_data_requests($user->id);
        $context = context_user::instance($user->id);
        $contextdatatowrite = [];
        foreach ($datarequests as $request) {
            $record = $request->to_record();
            $data = new stdClass();

            // The user ID that made the request/the request is made for.
            if ($record->requestedby != $record->userid) {
                if ($user->id != $record->requestedby) {
                    // This request is done by this user for another user.
                    $data->userid = fullname($user);
                } else if ($user->id != $record->userid) {
                    // This request was done by another user on behalf of this user.
                    $data->requestedby = fullname($user);
                }
            }

            // Request type.
            $data->type = tool_helper::get_shortened_request_type_string($record->type);
            // Status.
            $data->status = tool_helper::get_request_status_string($record->status);
            // Creation method.
            $data->creationmethod = tool_helper::get_request_creation_method_string($record->creationmethod);
            // Comments.
            $data->comments = $record->comments;
            // The DPO's comment about this request.
            $data->dpocomment = $record->dpocomment;
            // The date and time this request was lodged.
            $data->timecreated = transform::datetime($record->timecreated);
            $contextdatatowrite[] = $data;
        }

        // User context / Privacy and policies / Data requests.
        $subcontext = [
            get_string('privacyandpolicies', 'admin'),
            get_string('datarequests', 'tool_dataprivacy'),
        ];
        writer::with_context($context)->export_data($subcontext, (object)$contextdatatowrite);

        // Write generic module intro files.
        helper::export_context_files($context, $user);
    }