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

@param approved_contextlist $contextlist The approved contexts to export information for.
500710
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 bc.*
                  FROM {backup_controllers} bc
                  JOIN {context} ctx
                    ON ctx.instanceid = bc.itemid AND ctx.contextlevel = :contextlevel
                 WHERE ctx.id {$contextsql}
                   AND bc.userid = :userid
              ORDER BY bc.timecreated ASC";
        $params = ['contextlevel' => CONTEXT_COURSE, 'userid' => $user->id] + $contextparams;
        $backupcontrollers = $DB->get_recordset_sql($sql, $params);
        self::recordset_loop_and_export($backupcontrollers, 'itemid', [], function($carry, $record) {
            $carry[] = [
                'operation' => $record->operation,
                'type' => $record->type,
                'itemid' => $record->itemid,
                'timecreated' => transform::datetime($record->timecreated),
                'timemodified' => transform::datetime($record->timemodified),
            ];
            return $carry;
        }, function($courseid, $data) {
            $context = \context_course::instance($courseid);
            $finaldata = (object) $data;
            writer::with_context($context)->export_data([get_string('backup'), $courseid], $finaldata);
        });
    }
415263
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;
        if (!static::approved_contextlist_contains_my_context($contextlist)) {
            // We only care about the user's user context.
            return;
        }

        $userid = $contextlist->get_user()->id;
        $context = context_user::instance($userid);
        $path = [get_string('messageinbound', 'tool_messageinbound')];

        // Export user keys.
        \core_userkey\privacy\provider::export_userkeys($context, $path, 'messageinbound_handler');

        // Export the message list.
        $data = [];
        $recordset = $DB->get_recordset('messageinbound_messagelist', ['userid' => $userid], 'timecreated, id');
        foreach ($recordset as $record) {
            $data[] = [
                'received_at' => $record->address,
                'timecreated' => transform::datetime($record->timecreated),
            ];
        }
        $recordset->close();
        writer::with_context($context)->export_data($path, (object) ['messages_pending_validation' => $data]);
    }
1095159
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;
        $context = \context_system::instance();
        if (!$contextlist->count() || !in_array($context->id, $contextlist->get_contextids())) {
            return;
        }

        $user = $contextlist->get_user();
        $sql = "SELECT id, userid, tagcollid, name, rawname, isstandard, description, descriptionformat, flag, timemodified
            FROM {tag} WHERE userid = ?";
        $rs = $DB->get_recordset_sql($sql, [$user->id]);
        foreach ($rs as $record) {
            $subcontext = [get_string('tags', 'tag'), $record->id];
            $tag = (object)[
                'id' => $record->id,
                'userid' => transform::user($record->userid),
                'name' => $record->name,
                'rawname' => $record->rawname,
                'isstandard' => transform::yesno($record->isstandard),
                'description' => writer::with_context($context)->rewrite_pluginfile_urls($subcontext,
                    'tag', 'description', $record->id, strval($record->description)),
                'descriptionformat' => $record->descriptionformat,
                'flag' => $record->flag,
                'timemodified' => transform::datetime($record->timemodified),

            ];
            writer::with_context($context)->export_data($subcontext, $tag);
            writer::with_context($context)->export_area_files($subcontext, 'tag', 'description', $record->id);
        }
        $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);
    }
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]
            );
        }
    }
397491
public static function export_user_data(approved_contextlist $contextlist) {
        $results = static::get_records($contextlist->get_user()->id);
        $context = $contextlist->current();
        foreach ($results as $result) {
            $data = (object)[
                'appid' => $result->appid,
                'pushid' => $result->pushid,
                'name' => $result->name,
                'model' => $result->model,
                'platform' => $result->platform,
                'version' => $result->version,
                'timecreated' => transform::datetime($result->timecreated),
                'timemodified' => transform::datetime($result->timemodified),
                'enabled' => transform::yesno($result->enable)
            ];
            \core_privacy\local\request\writer::with_context($context)->export_data([
                    get_string('privacy:subcontext', 'message_airnotifier'),
                    $result->model . '_' . $result->pushid
                ], $data);
        }
    }
1092271
protected static function approved_contextlist_contains_my_context(approved_contextlist $contextlist) {
        $userid = $contextlist->get_user()->id;
        foreach ($contextlist->get_contexts() as $context) {
            if ($context->contextlevel == CONTEXT_USER && $context->instanceid == $userid) {
                return true;
            }
        }
        return false;
    }
155561
public static function delete_data_for_user(approved_contextlist $contextlist) {
        global $DB;

        // Questions are considered to be 'owned' by the institution, even if they were originally written by a specific
        // user. They are still exported in the list of a users data, but they are not removed.
        // The userid is instead anonymised.

        list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
        $contextparams['createdby'] = $contextlist->get_user()->id;
        $DB->set_field_select('question', 'createdby', 0, "
                category IN (SELECT id FROM {question_categories} WHERE contextid {$contextsql})
            AND createdby = :createdby", $contextparams);

        list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
        $contextparams['modifiedby'] = $contextlist->get_user()->id;
        $DB->set_field_select('question', 'modifiedby', 0, "
                category IN (SELECT id FROM {question_categories} WHERE contextid {$contextsql})
            AND modifiedby = :modifiedby", $contextparams);
    }
633899
public static function export_user_data(approved_contextlist $contextlist) {
        // If the user has data, then only the CONTEXT_USER should be present so get the first context.
        $contexts = $contextlist->get_contexts();
        if (count($contexts) == 0) {
            return;
        }
        $context = reset($contexts);

        // Sanity check that context is at the user context level, then get the userid.
        if ($context->contextlevel !== CONTEXT_USER) {
            return;
        }

        // Export associated userkeys.
        \core_userkey\privacy\provider::export_userkeys($context, [], 'rss');
    }
581359
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);
        $ratingquery = \core_rating\privacy\provider::get_sql_join('r', 'mod_glossary', 'entry', 'ge.id', $user->id);

        $sql = "SELECT ge.id as entryid,
                       cm.id AS cmid,
                       ge.userid,
                       ge.concept,
                       ge.definition,
                       ge.definitionformat,
                       ge.attachment,
                       ge.timecreated,
                       ge.timemodified
                  FROM {glossary_entries} ge
                  JOIN {glossary} g ON ge.glossaryid = g.id
                  JOIN {course_modules} cm ON g.id = cm.instance
                  JOIN {modules} m ON cm.module = m.id AND m.name = :modulename
                  JOIN {context} c ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
             LEFT JOIN {comments} com ON com.itemid = ge.id AND com.commentarea = :commentarea AND com.userid = :commentuserid
             {$ratingquery->join}
                 WHERE c.id {$contextsql}
                   AND (ge.userid = :userid OR com.id IS NOT NULL OR {$ratingquery->userwhere})
               ORDER BY ge.id, cm.id";
        $params = [
                'userid' => $user->id,
                'modulename' => 'glossary',
                'contextlevel' => CONTEXT_MODULE,
                'commentarea' => 'glossary_entry',
                'commentuserid' => $user->id
            ] + $contextparams;
        $params = array_merge($params, $ratingquery->params);
        $glossaryentries = $DB->get_recordset_sql($sql, $params);

        // Reference to the glossary 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 entries
        // for a new glossary activity and therefore when we can export the complete data for the last activity.
        $lastcmid = null;

        $glossarydata = [];
        foreach ($glossaryentries as $record) {
            $concept = format_string($record->concept);
            $path = array_merge([get_string('entries', 'mod_glossary'), $concept . " ({$record->entryid})"]);

            // If we've moved to a new glossary, then write the last glossary data and reinit the glossary data array.
            if (!is_null($lastcmid)) {
                if ($lastcmid != $record->cmid) {
                    if (!empty($glossarydata)) {
                        $context = \context_module::instance($lastcmid);
                        self::export_glossary_data_for_user($glossarydata, $context, [], $user);
                        $glossarydata = [];
                    }
                }
            }
            $lastcmid = $record->cmid;
            $context = \context_module::instance($lastcmid);

            // Export files added on the glossary entry definition field.
            $definition = format_text(writer::with_context($context)->rewrite_pluginfile_urls($path, 'mod_glossary',
                'entry',  $record->entryid, $record->definition), $record->definitionformat);

            // Export just the files attached to this user entry.
            if ($record->userid == $user->id) {
                // Get all files attached to the glossary attachment.
                writer::with_context($context)->export_area_files($path, 'mod_glossary', 'entry', $record->entryid);

                // Get all files attached to the glossary attachment.
                writer::with_context($context)->export_area_files($path, 'mod_glossary', 'attachment', $record->entryid);
            }

            // Export associated comments.
            \core_comment\privacy\provider::export_comments($context, 'mod_glossary', 'glossary_entry',
                    $record->entryid, $path, $record->userid != $user->id);

            // Export associated tags.
            \core_tag\privacy\provider::export_item_tags($user->id, $context, $path, 'mod_glossary', 'glossary_entries',
                    $record->entryid, $record->userid != $user->id);

            // Export associated ratings.
            \core_rating\privacy\provider::export_area_ratings($user->id, $context, $path, 'mod_glossary', 'entry',
                    $record->entryid, $record->userid != $user->id);

            $glossarydata['entries'][] = [
                'concept'       => $record->concept,
                'definition'    => $definition,
                'timecreated'   => \core_privacy\local\request\transform::datetime($record->timecreated),
                'timemodified'  => \core_privacy\local\request\transform::datetime($record->timemodified)
            ];
        }
        $glossaryentries->close();

        // The data for the last activity won't have been written yet, so make sure to write it now!
        if (!empty($glossarydata)) {
            $context = \context_module::instance($lastcmid);
            self::export_glossary_data_for_user($glossarydata, $context, [], $user);
        }
    }
284039
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;
        }

        // If the context export was requested, then let's at least describe the lesson.
        foreach ($cmids as $cmid) {
            $context = context_module::instance($cmid);
            $contextdata = helper::get_context_data($context, $user);
            helper::export_context_files($context, $user);
            writer::with_context($context)->export_data([], $contextdata);
        }

        // Find the lesson IDs.
        $lessonidstocmids = static::get_lesson_ids_to_cmids_from_cmids($cmids);

        // Prepare the common SQL fragments.
        list($inlessonsql, $inlessonparams) = $DB->get_in_or_equal(array_keys($lessonidstocmids), SQL_PARAMS_NAMED);
        $sqluserlesson = "userid = :userid AND lessonid $inlessonsql";
        $paramsuserlesson = array_merge($inlessonparams, ['userid' => $userid]);

        // Export the overrides.
        $recordset = $DB->get_recordset_select('lesson_overrides', $sqluserlesson, $paramsuserlesson);
        static::recordset_loop_and_export($recordset, 'lessonid', null, function($carry, $record) {
            // We know that there is only one row per lesson, so no need to use $carry.
            return (object) [
                'available' => $record->available !== null ? transform::datetime($record->available) : null,
                'deadline' => $record->deadline !== null ? transform::datetime($record->deadline) : null,
                'timelimit' => $record->timelimit !== null ? format_time($record->timelimit) : null,
                'review' => $record->review !== null ? transform::yesno($record->review) : null,
                'maxattempts' => $record->maxattempts,
                'retake' => $record->retake !== null ? transform::yesno($record->retake) : null,
                'password' => $record->password,
            ];
        }, function($lessonid, $data) use ($lessonidstocmids) {
            $context = context_module::instance($lessonidstocmids[$lessonid]);
            writer::with_context($context)->export_related_data([], 'overrides', $data);
        });

        // Export the grades.
        $recordset = $DB->get_recordset_select('lesson_grades', $sqluserlesson, $paramsuserlesson, 'lessonid, completed');
        static::recordset_loop_and_export($recordset, 'lessonid', [], function($carry, $record) {
            $carry[] = (object) [
                'grade' => $record->grade,
                'completed' => transform::datetime($record->completed),
            ];
            return $carry;
        }, function($lessonid, $data) use ($lessonidstocmids) {
            $context = context_module::instance($lessonidstocmids[$lessonid]);
            writer::with_context($context)->export_related_data([], 'grades', (object) ['grades' => $data]);
        });

        // Export the timers.
        $recordset = $DB->get_recordset_select('lesson_timer', $sqluserlesson, $paramsuserlesson, 'lessonid, starttime');
        static::recordset_loop_and_export($recordset, 'lessonid', [], function($carry, $record) {
            $carry[] = (object) [
                'starttime' => transform::datetime($record->starttime),
                'lastactivity' => transform::datetime($record->lessontime),
                'completed' => transform::yesno($record->completed),
                'timemodifiedoffline' => $record->timemodifiedoffline ? transform::datetime($record->timemodifiedoffline) : null,
            ];
            return $carry;
        }, function($lessonid, $data) use ($lessonidstocmids) {
            $context = context_module::instance($lessonidstocmids[$lessonid]);
            writer::with_context($context)->export_related_data([], 'timers', (object) ['timers' => $data]);
        });

        // Export the attempts and branches.
        $sql = "
            SELECT " . $DB->sql_concat('lp.id', "':'", 'COALESCE(la.id, 0)', "':'", 'COALESCE(lb.id, 0)') . " AS uniqid,
                   lp.lessonid,

                   lp.id AS page_id,
                   lp.qtype AS page_qtype,
                   lp.qoption AS page_qoption,
                   lp.title AS page_title,
                   lp.contents AS page_contents,
                   lp.contentsformat AS page_contentsformat,

                   la.id AS attempt_id,
                   la.retry AS attempt_retry,
                   la.correct AS attempt_correct,
                   la.useranswer AS attempt_useranswer,
                   la.timeseen AS attempt_timeseen,

                   lb.id AS branch_id,
                   lb.retry AS branch_retry,
                   lb.timeseen AS branch_timeseen,

                   lpb.id AS nextpage_id,
                   lpb.title AS nextpage_title

              FROM {lesson_pages} lp
         LEFT JOIN {lesson_attempts} la
                ON la.pageid = lp.id
               AND la.userid = :userid1
         LEFT JOIN {lesson_branch} lb
                ON lb.pageid = lp.id
               AND lb.userid = :userid2
         LEFT JOIN {lesson_pages} lpb
                ON lpb.id = lb.nextpageid
             WHERE lp.lessonid $inlessonsql
               AND (la.id IS NOT NULL OR lb.id IS NOT NULL)
          ORDER BY lp.lessonid, lp.id, la.retry, lb.retry, la.id, lb.id";
        $params = array_merge($inlessonparams, ['userid1' => $userid, 'userid2' => $userid]);

        $recordset = $DB->get_recordset_sql($sql, $params);
        static::recordset_loop_and_export($recordset, 'lessonid', [], function($carry, $record) use ($lessonidstocmids) {
            $context = context_module::instance($lessonidstocmids[$record->lessonid]);
            $options = ['context' => $context];

            $take = isset($record->attempt_retry) ? $record->attempt_retry : $record->branch_retry;
            if (!isset($carry[$take])) {
                $carry[$take] = (object) [
                    'number' => $take + 1,
                    'answers' => [],
                    'jumps' => []
                ];
            }

            $pagefilespath = [get_string('privacy:path:pages', 'mod_lesson'), $record->page_id];
            writer::with_context($context)->export_area_files($pagefilespath, 'mod_lesson', 'page_contents', $record->page_id);
            $pagecontents = format_text(
                writer::with_context($context)->rewrite_pluginfile_urls(
                    $pagefilespath,
                    'mod_lesson',
                    'page_contents',
                    $record->page_id,
                    $record->page_contents
                ),
                $record->page_contentsformat,
                $options
            );

            $pagebase = [
                'id' => $record->page_id,
                'page' => $record->page_title,
                'contents' => $pagecontents,
                'contents_files_folder' => implode('/', $pagefilespath)
            ];

            if (isset($record->attempt_id)) {
                $carry[$take]->answers[] = array_merge($pagebase, static::transform_attempt($record, $context));

            } else if (isset($record->branch_id)) {
                if (!empty($record->nextpage_id)) {
                    $wentto = $record->nextpage_title . " (id: {$record->nextpage_id})";
                } else {
                    $wentto = get_string('endoflesson', 'mod_lesson');
                }
                $carry[$take]->jumps[] = array_merge($pagebase, [
                    'went_to' => $wentto,
                    'timeseen' => transform::datetime($record->attempt_timeseen)
                ]);
            }

            return $carry;

        }, function($lessonid, $data) use ($lessonidstocmids) {
            $context = context_module::instance($lessonidstocmids[$lessonid]);
            writer::with_context($context)->export_related_data([], 'attempts', (object) [
                'attempts' => array_values($data)
            ]);
        });
    }
135795
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        if (empty($contextlist->count())) {
            return;
        }
        $userid = $contextlist->get_user()->id;
        list($insql, $inparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
        $params = [
            'contextlevel' => CONTEXT_COURSE,
            'userid' => $userid
         ];
        $params += $inparams;
        $sql = "SELECT ue.id,
                       ue.status,
                       ue.timestart,
                       ue.timeend,
                       ue.timecreated,
                       ue.timemodified,
                       e.enrol,
                       ctx.id as contextid
                  FROM {user_enrolments} ue
                  JOIN {enrol} e
                    ON e.id = ue.enrolid
                   AND ue.userid = :userid
                  JOIN {context} ctx
                    ON ctx.instanceid = e.courseid
                   AND ctx.contextlevel = :contextlevel
                 WHERE ctx.id $insql
                 ORDER BY ctx.id, e.enrol";
        $data = [];
        $lastcontextid = null;
        $lastenrol = null;
        $path = [get_string('privacy:metadata:user_enrolments', 'core_enrol')];
        $flush = function($lastcontextid, $lastenrol, $data) use ($path) {
            $context = \context::instance_by_id($lastcontextid);
            writer::with_context($context)->export_related_data(
                $path,
                $lastenrol,
                (object)$data
            );
        };
        $userenrolments = $DB->get_recordset_sql($sql, $params);
        foreach ($userenrolments as $userenrolment) {
            if (($lastcontextid && $lastcontextid != $userenrolment->contextid) ||
                    ($lastenrol && $lastenrol != $userenrolment->enrol)) {
                $flush($lastcontextid, $lastenrol, $data);
                $data = [];
            }
            $data[] = (object) [
                'status' => $userenrolment->status,
                'timecreated' => transform::datetime($userenrolment->timecreated),
                'timemodified' => transform::datetime($userenrolment->timemodified),
                'timestart' => transform::datetime($userenrolment->timestart),
                'timeend' => transform::datetime($userenrolment->timeend)
            ];
            $lastcontextid = $userenrolment->contextid;
            $lastenrol = $userenrolment->enrol;
        }
        if (!empty($data)) {
            $flush($lastcontextid, $lastenrol, $data);
        }
        $userenrolments->close();
    }
966617
public static function export_user_data(approved_contextlist $contextlist) {
        if (empty($contextlist->count())) {
            return;
        }

        $user = $contextlist->get_user();

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

            // Cannot make use of helper::export_context_files(), need to manually export assignment details.
            $assignmentdata = self::get_assignment_by_context($context);

            // Get assignment details object for output.
            $assignment = self::get_assignment_output($assignmentdata);
            writer::with_context($context)->export_data([], $assignment);

            // Check if the user has marked any assignment's submissions to determine assignment submissions to export.
            $teacher = (self::has_marked_assignment_submissions($assignmentdata->id, $user->id) == true) ? true : false;

            // Get the assignment submissions submitted by & marked by the user for an assignment.
            $submissionsdata = self::get_assignment_submissions_by_assignment($assignmentdata->id, $user->id, $teacher);

            foreach ($submissionsdata as $submissiondata) {
                // Default subcontext path to export assignment submissions submitted by the user.
                $subcontexts = [
                    get_string('privacy:submissionpath', 'mod_assignment')
                ];

                if ($teacher == true) {
                    if ($submissiondata->teacher == $user->id) {
                        // Export assignment submissions that have been marked by the user.
                        $subcontexts = [
                            get_string('privacy:markedsubmissionspath', 'mod_assignment'),
                            transform::user($submissiondata->userid)
                        ];
                    }
                }

                // Get assignment submission details object for output.
                $submission = self::get_assignment_submission_output($submissiondata);
                $itemid = $submissiondata->id;

                writer::with_context($context)
                    ->export_data($subcontexts, $submission)
                    ->export_area_files($subcontexts, 'mod_assignment', 'submission', $itemid);
            }
        }
    }
1362479
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        // If the user has data, then only the User context should be present so get the first context.
        $contexts = $contextlist->get_contexts();
        if (count($contexts) == 0) {
            return;
        }
        $context = reset($contexts);

        // Sanity check that context is at the User context level, then get the userid.
        if ($context->contextlevel !== CONTEXT_USER) {
            return;
        }
        $userid = $context->instanceid;

        $sql = "SELECT roa.id as id,
                       roa.itemid as itemid,
                       roa.permissionid as permissionid,
                       roa.timecreated as timecreated,
                       roa.timemodified as timemodified
                  FROM {repository_onedrive_access} roa
                 WHERE roa.usermodified = :userid";

        $params = [
            'userid' => $userid
        ];

        $onedriveaccesses = $DB->get_records_sql($sql, $params);
        $index = 0;
        foreach ($onedriveaccesses as $onedriveaccess) {
            // Data export is organised in: {User Context}/Repository plug-ins/{Plugin Name}/Access/{index}/data.json.
            $index++;
            $subcontext = [
                get_string('plugin', 'core_repository'),
                get_string('pluginname', 'repository_onedrive'),
                get_string('access', 'repository_onedrive'),
                $index
            ];

            $data = (object) [
                'itemid' => $onedriveaccess->itemid,
                'permissionid' => $onedriveaccess->permissionid,
                'timecreated' => transform::datetime($onedriveaccess->timecreated),
                'timemodified' => transform::datetime($onedriveaccess->timemodified)
            ];

            writer::with_context($context)->export_data($subcontext, $data);
        }

    }
88427
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        if (!count($contextlist)) {
            return;
        }

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

        $sql = "SELECT
                    q.*,
                    qg.id AS hasgrade,
                    qg.grade AS bestgrade,
                    qg.timemodified AS grademodified,
                    qo.id AS hasoverride,
                    qo.timeopen AS override_timeopen,
                    qo.timeclose AS override_timeclose,
                    qo.timelimit AS override_timelimit,
                    c.id AS contextid,
                    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 {quiz} q ON q.id = cm.instance
             LEFT JOIN {quiz_overrides} qo ON qo.quiz = q.id AND qo.userid = :qouserid
             LEFT JOIN {quiz_grades} qg ON qg.quiz = q.id AND qg.userid = :qguserid
                 WHERE c.id {$contextsql}";

        $params = [
            'contextlevel'      => CONTEXT_MODULE,
            'modname'           => 'quiz',
            'qguserid'          => $userid,
            'qouserid'          => $userid,
        ];
        $params += $contextparams;

        // Fetch the individual quizzes.
        $quizzes = $DB->get_recordset_sql($sql, $params);
        foreach ($quizzes as $quiz) {
            list($course, $cm) = get_course_and_cm_from_cmid($quiz->cmid, 'quiz');
            $quizobj = new \quiz($quiz, $cm, $course);
            $context = $quizobj->get_context();

            $quizdata = \core_privacy\local\request\helper::get_context_data($context, $contextlist->get_user());
            \core_privacy\local\request\helper::export_context_files($context, $contextlist->get_user());

            if (!empty($quizdata->timeopen)) {
                $quizdata->timeopen = transform::datetime($quiz->timeopen);
            }
            if (!empty($quizdata->timeclose)) {
                $quizdata->timeclose = transform::datetime($quiz->timeclose);
            }
            if (!empty($quizdata->timelimit)) {
                $quizdata->timelimit = $quiz->timelimit;
            }

            if (!empty($quiz->hasoverride)) {
                $quizdata->override = (object) [];

                if (!empty($quizdata->override_override_timeopen)) {
                    $quizdata->override->timeopen = transform::datetime($quiz->override_timeopen);
                }
                if (!empty($quizdata->override_timeclose)) {
                    $quizdata->override->timeclose = transform::datetime($quiz->override_timeclose);
                }
                if (!empty($quizdata->override_timelimit)) {
                    $quizdata->override->timelimit = $quiz->override_timelimit;
                }
            }

            $quizdata->accessdata = (object) [];

            $components = \core_component::get_plugin_list('quizaccess');
            $exportparams = [
                    $quizobj,
                    $user,
                ];
            foreach (array_keys($components) as $component) {
                $classname = manager::get_provider_classname_for_component("quizaccess_$component");
                if (class_exists($classname) && is_subclass_of($classname, quizaccess_provider::class)) {
                    $result = component_class_callback($classname, 'export_quizaccess_user_data', $exportparams);
                    if (count((array) $result)) {
                        $quizdata->accessdata->$component = $result;
                    }
                }
            }

            if (empty((array) $quizdata->accessdata)) {
                unset($quizdata->accessdata);
            }

            writer::with_context($context)
                ->export_data([], $quizdata);
        }
        $quizzes->close();

        // Store all quiz attempt data.
        static::export_quiz_attempts($contextlist);
    }
769456
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        // If the user has repository_instances data, then only the User context should be present so get the first context.
        $contexts = $contextlist->get_contexts();
        if (count($contexts) == 0) {
            return;
        }
        $context = reset($contexts);

        // Sanity check that context is at the User context level, then get the userid.
        if ($context->contextlevel !== CONTEXT_USER) {
            return;
        }
        $userid = $context->instanceid;

        $sql = "SELECT DISTINCT
                       ri.id as id,
                       r.type as type,
                       ri.name as name,
                       ri.timecreated as timecreated,
                       ri.timemodified as timemodified
                  FROM {repository_instances} ri
                  JOIN {repository} r ON r.id = ri.typeid
                 WHERE ri.userid = :userid";

        $params = [
            'userid' => $userid
        ];

        $repositoryinstances = $DB->get_records_sql($sql, $params);

        foreach ($repositoryinstances as $repositoryinstance) {
            // The repository_instances data export is organised in: {User Context}/Repository plug-ins/{Plugin Name}/data.json.
            $subcontext = [
                get_string('plugin', 'core_repository'),
                get_string('pluginname', 'repository_' . $repositoryinstance->type)
            ];

            $data = (object) [
                'type' => $repositoryinstance->type,
                'name' => $repositoryinstance->name,
                'timecreated' => transform::datetime($repositoryinstance->timecreated),
                'timemodified' => transform::datetime($repositoryinstance->timemodified)
            ];

            writer::with_context($context)->export_data($subcontext, $data);
        }
    }
1111698
public static function delete_data_for_user(approved_contextlist $contextlist) {
        global $DB;

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

        $userid = $contextlist->get_user()->id;
        foreach ($contextlist->get_contexts() as $context) {
            if ($context instanceof \context_course) {
                $select = "itemid = :itemid AND userid = :userid AND type = :type";
                $params = [
                    'userid' => $userid,
                    'itemid' => $context->instanceid,
                    'type' => \backup::TYPE_1COURSE
                ];

                $DB->delete_records_select('backup_controllers', $select, $params);

                $params = [
                    'userid' => $userid,
                    'course' => $context->instanceid,
                    'type' => \backup::TYPE_1SECTION
                ];
                $sectionsql = "itemid IN (SELECT id FROM {course_sections} WHERE course = :course)";
                $select = $sectionsql . " AND userid = :userid AND type = :type";
                $DB->delete_records_select('backup_controllers', $select, $params);
            }
            if ($context instanceof \context_module) {
                list($usersql, $userparams) = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED);
                $select = "itemid = :itemid AND userid = :userid AND type = :type";
                $params = [
                    'itemid' => $context->instanceid,
                    'userid' => $userid,
                    'type' => \backup::TYPE_1ACTIVITY
                ];

                $DB->delete_records_select('backup_controllers', $select, $params);
            }

        }
    }