Export the user data related to templates in contexts.

@param int $userid The user ID.
@param context $context The context.
@return void
423361
protected static function export_user_data_templates_in_context($userid, context $context) {
        global $DB;

        $tfields = template::get_sql_fields('t', 't_');
        $cfields = competency::get_sql_fields('c', 'c_');
        $tcfields = template_competency::get_sql_fields('tc', 'tc_');
        $tchfields = template_cohort::get_sql_fields('tch', 'tch_');

        $templates = [];
        $inittemplate = function($record) use (&$templates, $userid) {
            $template = new template(null, template::extract_record($record, 't_'));
            $templates[$template->get('id')] = array_merge(static::transform_template_brief($template), [
                'timemodified' => transform::datetime($template->get('timemodified')),
                'created_or_modified_by_you' => transform::yesno($template->get('usermodified') == $userid),
                'competencies' => [],
                'cohorts' => []
            ]);
        };

        // Find the template competencies.
        $sql = "
            SELECT $tfields, $cfields, $tcfields
              FROM {" . template_competency::TABLE . "} tc
              JOIN {" . template::TABLE . "} t
                ON t.id = tc.templateid
              JOIN {" . competency::TABLE . "} c
                ON c.id = tc.competencyid
             WHERE t.contextid = :contextid
               AND tc.usermodified = :userid
          ORDER BY t.id, tc.id";
        $params = ['userid' => $userid, 'contextid' => $context->id];
        $recordset = $DB->get_recordset_sql($sql, $params);
        foreach ($recordset as $record) {
            $templateid = $record->t_id;
            if (!isset($templates[$templateid])) {
                $inittemplate($record);
            }
            $tplcomp = new template_competency(null, template_competency::extract_record($record, 'tc_'));
            $competency = new competency(null, competency::extract_record($record, 'c_'));
            $templates[$templateid]['competencies'][] = array_merge(
                static::transform_competency_brief($competency),
                [
                    'timemodified' => transform::datetime($tplcomp->get('timemodified')),
                    'created_or_modified_by_you' => transform::yesno($tplcomp->get('usermodified') == $userid)
                ]
            );
        }
        $recordset->close();

        // Find the template cohorts.
        $sql = "
            SELECT $tfields, $tchfields, c.name AS cohortname
              FROM {" . template_cohort::TABLE . "} tch
              JOIN {" . template::TABLE . "} t
                ON t.id = tch.templateid
              JOIN {cohort} c
                ON c.id = tch.cohortid
             WHERE t.contextid = :contextid
               AND tch.usermodified = :userid
          ORDER BY t.id, tch.id";
        $params = ['userid' => $userid, 'contextid' => $context->id];
        $recordset = $DB->get_recordset_sql($sql, $params);
        foreach ($recordset as $record) {
            $templateid = $record->t_id;
            if (!isset($templates[$templateid])) {
                $inittemplate($record);
            }
            $tplcohort = new template_cohort(null, template_cohort::extract_record($record, 'tch_'));
            $templates[$templateid]['cohorts'][] = [
                'name' => $record->cohortname,
                'timemodified' => transform::datetime($tplcohort->get('timemodified')),
                'created_or_modified_by_you' => transform::yesno($tplcohort->get('usermodified') == $userid)
            ];
        }
        $recordset->close();

        // Find the modified templates which we haven't been found yet.
        $templateids = array_keys($templates);
        $insql = "IS NOT NULL";
        $inparams = [];
        if (!empty($templateids)) {
            list($insql, $inparams) = $DB->get_in_or_equal($templateids, SQL_PARAMS_NAMED, 'param', false);
        }
        $sql = "
            SELECT $tfields
              FROM {" . template::TABLE . "} t
             WHERE t.contextid = :contextid
               AND t.usermodified = :userid
               AND t.id $insql
          ORDER BY t.id";
        $params = array_merge($inparams, ['userid' => $userid, 'contextid' => $context->id]);
        $recordset = $DB->get_recordset_sql($sql, $params);
        foreach ($recordset as $record) {
            $inittemplate($record);
        }
        $recordset->close();

        // Export all the things!
        writer::with_context($context)->export_related_data([get_string('competencies', 'core_competency')],
            'templates', (object) ['templates' => array_values($templates)]);
    }
1027953
public static function add_contexts_for_userid(contextlist $contextlist, $userid) {
        $sql = "
            SELECT ctx.id
              FROM {context} ctx
              JOIN {log} l
                ON (l.cmid = 0 AND l.course = ctx.instanceid AND ctx.contextlevel = :courselevel)
                OR (l.cmid > 0 AND l.cmid = ctx.instanceid AND ctx.contextlevel = :modulelevel)
                OR (l.course <= 0 AND ctx.id = :syscontextid)
             WHERE l.userid = :userid";
        $params = [
            'courselevel' => CONTEXT_COURSE,
            'modulelevel' => CONTEXT_MODULE,
            'syscontextid' => SYSCONTEXTID,
            'userid' => $userid,
        ];
        $contextlist->add_from_sql($sql, $params);
    }
1251168
protected static function export_password_history(int $userid, \context $context) {
        global $DB;

        // Just provide a count of how many entries we have.
        $recordcount = $DB->count_records('user_password_history', ['userid' => $userid]);
        if ($recordcount) {
            $passwordhistory = (object) ['password_history_count' => $recordcount];
            writer::with_context($context)->export_data([get_string('privacy:passwordhistorypath', 'user')], $passwordhistory);
        }
    }
1299096
public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        $user = $contextlist->get_user();
        $userid = $user->id;
        $contexts = array_reduce($contextlist->get_contexts(), function($carry, $context) use ($userid) {
            if ($context->contextlevel == CONTEXT_COURSE) {
                $carry[$context->contextlevel][] = $context;

            } else if ($context->contextlevel == CONTEXT_USER) {
                $carry[$context->contextlevel][] = $context;

            }

            return $carry;
        }, [
            CONTEXT_USER => [],
            CONTEXT_COURSE => []
        ]);

        $rootpath = [get_string('grades', 'core_grades')];
        $relatedtomepath = array_merge($rootpath, [get_string('privacy:path:relatedtome', 'core_grades')]);

        // Export the outcomes.
        static::export_user_data_outcomes_in_contexts($contextlist);

        // Export the scales.
        static::export_user_data_scales_in_contexts($contextlist);

        // Export the historical grades which have become orphans (their grade items were deleted).
        // We place those in ther user context of the graded user.
        $userids = array_values(array_map(function($context) {
            return $context->instanceid;
        }, $contexts[CONTEXT_USER]));
        if (!empty($userids)) {

            // Export own historical grades and related ones.
            list($inuseridsql, $inuseridparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
            list($inusermodifiedsql, $inusermodifiedparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
            list($inloggedusersql, $inloggeduserparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
            $usercontext = $contexts[CONTEXT_USER];
            $gghfields = static::get_fields_sql('grade_grades_history', 'ggh', 'ggh_');
            $sql = "
                SELECT $gghfields, ctx.id as ctxid
                  FROM {grade_grades_history} ggh
                  JOIN {context} ctx
                    ON ctx.instanceid = ggh.userid
                   AND ctx.contextlevel = :userlevel
             LEFT JOIN {grade_items} gi
                    ON gi.id = ggh.itemid
                 WHERE gi.id IS NULL
                   AND (ggh.userid $inuseridsql
                    OR ggh.usermodified $inusermodifiedsql
                    OR ggh.loggeduser $inloggedusersql)
                   AND (ggh.userid = :userid1
                    OR ggh.usermodified = :userid2
                    OR ggh.loggeduser = :userid3)
              ORDER BY ggh.userid, ggh.timemodified, ggh.id";
            $params = array_merge($inuseridparams, $inusermodifiedparams, $inloggeduserparams,
                ['userid1' => $userid, 'userid2' => $userid, 'userid3' => $userid, 'userlevel' => CONTEXT_USER]);

            $deletedstr = get_string('privacy:request:unknowndeletedgradeitem', 'core_grades');
            $recordset = $DB->get_recordset_sql($sql, $params);
            static::recordset_loop_and_export($recordset, 'ctxid', [], function($carry, $record) use ($deletedstr, $userid) {
                $context = context::instance_by_id($record->ctxid);
                $gghrecord = static::extract_record($record, 'ggh_');

                // Orphan grades do not have items, so we do not recreate a grade_grade item, and we do not format grades.
                $carry[] = [
                    'name' => $deletedstr,
                    'graded_user_was_you' => transform::yesno($userid == $gghrecord->userid),
                    'grade' => $gghrecord->finalgrade,
                    'feedback' => format_text($gghrecord->feedback, $gghrecord->feedbackformat, ['context' => $context]),
                    'information' => format_text($gghrecord->information, $gghrecord->informationformat, ['context' => $context]),
                    'timemodified' => transform::datetime($gghrecord->timemodified),
                    'logged_in_user_was_you' => transform::yesno($userid == $gghrecord->loggeduser),
                    'author_of_change_was_you' => transform::yesno($userid == $gghrecord->usermodified),
                    'action' => static::transform_history_action($gghrecord->action)
                ];

                return $carry;

            }, function($ctxid, $data) use ($rootpath) {
                $context = context::instance_by_id($ctxid);
                writer::with_context($context)->export_related_data($rootpath, 'history', (object) ['grades' => $data]);
            });
        }

        // Find out the course IDs.
        $courseids = array_values(array_map(function($context) {
            return $context->instanceid;
        }, $contexts[CONTEXT_COURSE]));
        if (empty($courseids)) {
            return;
        }
        list($incoursesql, $incourseparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED);

        // Ensure that the grades are final and do not need regrading.
        array_walk($courseids, function($courseid) {
            grade_regrade_final_grades($courseid);
        });

        // Export own grades.
        $ggfields = static::get_fields_sql('grade_grade', 'gg', 'gg_');
        $gifields = static::get_fields_sql('grade_item', 'gi', 'gi_');
        $scalefields = static::get_fields_sql('grade_scale', 'sc', 'sc_');
        $sql = "
            SELECT $ggfields, $gifields, $scalefields
              FROM {grade_grades} gg
              JOIN {grade_items} gi
                ON gi.id = gg.itemid
         LEFT JOIN {scale} sc
                ON sc.id = gi.scaleid
             WHERE gi.courseid $incoursesql
               AND gg.userid = :userid
          ORDER BY gi.courseid, gi.id, gg.id";
        $params = array_merge($incourseparams, ['userid' => $userid]);

        $recordset = $DB->get_recordset_sql($sql, $params);
        static::recordset_loop_and_export($recordset, 'gi_courseid', [], function($carry, $record) {
            $context = context_course::instance($record->gi_courseid);
            $gg = static::extract_grade_grade_from_record($record);
            $carry[] = static::transform_grade($gg, $context, false);

            return $carry;

        }, function($courseid, $data) use ($rootpath) {
            $context = context_course::instance($courseid);

            $pathtofiles = [
                get_string('grades', 'core_grades'),
                get_string('feedbackfiles', 'core_grades')
            ];
            foreach ($data as $key => $grades) {
                $gg = $grades['gradeobject'];
                writer::with_context($gg->get_context())->export_area_files($pathtofiles, GRADE_FILE_COMPONENT,
                    GRADE_FEEDBACK_FILEAREA, $gg->id);
                unset($data[$key]['gradeobject']); // Do not want to export this later.
            }

            writer::with_context($context)->export_data($rootpath, (object) ['grades' => $data]);
        });

        // Export own historical grades in courses.
        $gghfields = static::get_fields_sql('grade_grades_history', 'ggh', 'ggh_');
        $sql = "
            SELECT $gghfields, $gifields, $scalefields
              FROM {grade_grades_history} ggh
              JOIN {grade_items} gi
                ON gi.id = ggh.itemid
         LEFT JOIN {scale} sc
                ON sc.id = gi.scaleid
             WHERE gi.courseid $incoursesql
               AND ggh.userid = :userid
          ORDER BY gi.courseid, ggh.timemodified, ggh.id";
        $params = array_merge($incourseparams, ['userid' => $userid]);

        $recordset = $DB->get_recordset_sql($sql, $params);
        static::recordset_loop_and_export($recordset, 'gi_courseid', [], function($carry, $record) {
            $context = context_course::instance($record->gi_courseid);
            $gg = static::extract_grade_grade_from_record($record, true);
            $carry[] = array_merge(static::transform_grade($gg, $context, true), [
                'action' => static::transform_history_action($record->ggh_action)
            ]);
            return $carry;

        }, function($courseid, $data) use ($rootpath) {
            $context = context_course::instance($courseid);

            $pathtofiles = [
                get_string('grades', 'core_grades'),
                get_string('feedbackhistoryfiles', 'core_grades')
            ];
            foreach ($data as $key => $grades) {
                $gg = $grades['gradeobject'];
                writer::with_context($gg->get_context())->export_area_files($pathtofiles, GRADE_FILE_COMPONENT,
                    GRADE_HISTORY_FEEDBACK_FILEAREA, $gg->historyid);
                unset($data[$key]['gradeobject']); // Do not want to export this later.
            }

            writer::with_context($context)->export_related_data($rootpath, 'history', (object) ['grades' => $data]);
        });

        // Export edits of categories history.
        $sql = "
            SELECT gch.id, gch.courseid, gch.fullname, gch.timemodified, gch.action
              FROM {grade_categories_history} gch
             WHERE gch.courseid $incoursesql
               AND gch.loggeduser = :userid
          ORDER BY gch.courseid, gch.timemodified, gch.id";
        $params = array_merge($incourseparams, ['userid' => $userid]);
        $recordset = $DB->get_recordset_sql($sql, $params);
        static::recordset_loop_and_export($recordset, 'courseid', [], function($carry, $record) {
            $carry[] = [
                'name' => $record->fullname,
                'timemodified' => transform::datetime($record->timemodified),
                'logged_in_user_was_you' => transform::yesno(true),
                'action' => static::transform_history_action($record->action),
            ];
            return $carry;

        }, function($courseid, $data) use ($relatedtomepath) {
            $context = context_course::instance($courseid);
            writer::with_context($context)->export_related_data($relatedtomepath, 'categories_history',
                (object) ['modified_records' => $data]);
        });

        // Export edits of items history.
        $sql = "
            SELECT gih.id, gih.courseid, gih.itemname, gih.itemmodule, gih.iteminfo, gih.timemodified, gih.action
              FROM {grade_items_history} gih
             WHERE gih.courseid $incoursesql
               AND gih.loggeduser = :userid
          ORDER BY gih.courseid, gih.timemodified, gih.id";
        $params = array_merge($incourseparams, ['userid' => $userid]);
        $recordset = $DB->get_recordset_sql($sql, $params);
        static::recordset_loop_and_export($recordset, 'courseid', [], function($carry, $record) {
            $carry[] = [
                'name' => $record->itemname,
                'module' => $record->itemmodule,
                'info' => $record->iteminfo,
                'timemodified' => transform::datetime($record->timemodified),
                'logged_in_user_was_you' => transform::yesno(true),
                'action' => static::transform_history_action($record->action),
            ];
            return $carry;

        }, function($courseid, $data) use ($relatedtomepath) {
            $context = context_course::instance($courseid);
            writer::with_context($context)->export_related_data($relatedtomepath, 'items_history',
                (object) ['modified_records' => $data]);
        });

        // Export edits of grades in course.
        $sql = "
            SELECT $ggfields, $gifields, $scalefields
              FROM {grade_grades} gg
              JOIN {grade_items} gi
                ON gg.itemid = gi.id
         LEFT JOIN {scale} sc
                ON sc.id = gi.scaleid
             WHERE gi.courseid $incoursesql
               AND gg.userid <> :userid1    -- Our grades have already been exported.
               AND gg.usermodified = :userid2
          ORDER BY gi.courseid, gg.timemodified, gg.id";
        $params = array_merge($incourseparams, ['userid1' => $userid, 'userid2' => $userid]);
        $recordset = $DB->get_recordset_sql($sql, $params);
        static::recordset_loop_and_export($recordset, 'gi_courseid', [], function($carry, $record) {
            $context = context_course::instance($record->gi_courseid);
            $gg = static::extract_grade_grade_from_record($record);
            $carry[] = array_merge(static::transform_grade($gg, $context, false), [
                'userid' => transform::user($gg->userid),
                'created_or_modified_by_you' => transform::yesno(true),
            ]);
            return $carry;

        }, function($courseid, $data) use ($relatedtomepath) {
            $context = context_course::instance($courseid);

            $pathtofiles = [
                get_string('grades', 'core_grades'),
                get_string('feedbackfiles', 'core_grades')
            ];
            foreach ($data as $key => $grades) {
                $gg = $grades['gradeobject'];
                writer::with_context($gg->get_context())->export_area_files($pathtofiles, GRADE_FILE_COMPONENT,
                    GRADE_FEEDBACK_FILEAREA, $gg->id);
                unset($data[$key]['gradeobject']); // Do not want to export this later.
            }

            writer::with_context($context)->export_related_data($relatedtomepath, 'grades', (object) ['grades' => $data]);
        });

        // Export edits of grades history in course.
        $sql = "
            SELECT $gghfields, $gifields, $scalefields, ggh.loggeduser AS loggeduser
              FROM {grade_grades_history} ggh
              JOIN {grade_items} gi
                ON ggh.itemid = gi.id
         LEFT JOIN {scale} sc
                ON sc.id = gi.scaleid
             WHERE gi.courseid $incoursesql
               AND ggh.userid <> :userid1   -- We've already exported our history.
               AND (ggh.loggeduser = :userid2
                OR ggh.usermodified = :userid3)
          ORDER BY gi.courseid, ggh.timemodified, ggh.id";
        $params = array_merge($incourseparams, ['userid1' => $userid, 'userid2' => $userid, 'userid3' => $userid]);
        $recordset = $DB->get_recordset_sql($sql, $params);
        static::recordset_loop_and_export($recordset, 'gi_courseid', [], function($carry, $record) use ($userid) {
            $context = context_course::instance($record->gi_courseid);
            $gg = static::extract_grade_grade_from_record($record, true);
            $carry[] = array_merge(static::transform_grade($gg, $context, true), [
                'userid' => transform::user($gg->userid),
                'logged_in_user_was_you' => transform::yesno($userid == $record->loggeduser),
                'author_of_change_was_you' => transform::yesno($userid == $gg->usermodified),
                'action' => static::transform_history_action($record->ggh_action),
            ]);
            return $carry;

        }, function($courseid, $data) use ($relatedtomepath) {
            $context = context_course::instance($courseid);

            $pathtofiles = [
                get_string('grades', 'core_grades'),
                get_string('feedbackhistoryfiles', 'core_grades')
            ];
            foreach ($data as $key => $grades) {
                $gg = $grades['gradeobject'];
                writer::with_context($gg->get_context())->export_area_files($pathtofiles, GRADE_FILE_COMPONENT,
                    GRADE_HISTORY_FEEDBACK_FILEAREA, $gg->historyid);
                unset($data[$key]['gradeobject']); // Do not want to export this later.
            }

            writer::with_context($context)->export_related_data($relatedtomepath, 'grades_history',
                (object) ['modified_records' => $data]);
        });
    }
944492
protected static function export_user_data_competencies(context_user $context) {
        global $DB;

        $userid = $context->instanceid;
        $path = [get_string('competencies', 'core_competency'), get_string('competencies', 'core_competency')];
        $helper = new performance_helper();
        $cfields = competency::get_sql_fields('c', 'c_');
        $ucfields = user_competency::get_sql_fields('uc', 'uc_');
        $efields = evidence::get_sql_fields('e', 'e_');

        $makecomppath = function($competencyid, $data) use ($path) {
            return array_merge($path, [$data['name'] . ' (' . $competencyid . ')']);
        };

        $sql = "
            SELECT $cfields, $ucfields, $efields
              FROM {" . user_competency::TABLE . "} uc
              JOIN {" . competency::TABLE . "} c
                ON c.id = uc.competencyid
         LEFT JOIN {" . evidence::TABLE . "} e
                ON uc.id = e.usercompetencyid
             WHERE uc.userid = :userid
          ORDER BY c.id, e.timecreated DESC, e.id DESC";
        $params = ['userid' => $userid];

        $recordset = $DB->get_recordset_sql($sql, $params);
        static::recordset_loop_and_export($recordset, 'c_id', null, function($carry, $record)
                use ($context, $userid, $helper, $makecomppath) {

            $competency = new competency(null, competency::extract_record($record, 'c_'));

            if ($carry === null) {
                $uc = new user_competency(null, user_competency::extract_record($record, 'uc_'));
                $carry = array_merge(static::transform_competency_brief($competency), [
                    'rating' => static::transform_user_competency($userid, $uc, $competency, $helper),
                    'evidence' => []
                ]);
                \core_comment\privacy\provider::export_comments($context, 'competency', 'user_competency',
                    $uc->get('id'), $makecomppath($competency->get('id'), $carry), false);
            }

            // There is an evidence in this record.
            if (!empty($record->e_id)) {
                $evidence = new evidence(null, evidence::extract_record($record, 'e_'));
                $carry['evidence'][] = static::transform_evidence($userid, $evidence, $competency, $helper);
            }

            return $carry;

        }, function($competencyid, $data) use ($makecomppath, $context) {
            writer::with_context($context)->export_data($makecomppath($competencyid, $data), (object) $data);
        });
    }
1365169
public static function export_user_preferences(int $userid) {
        static::get_and_export_user_preference($userid, 'scorm_report_pagesize');
        static::get_and_export_user_preference($userid, 'scorm_report_interactions_qtext', true);
        static::get_and_export_user_preference($userid, 'scorm_report_interactions_resp', true);
        static::get_and_export_user_preference($userid, 'scorm_report_interactions_right', true);
        static::get_and_export_user_preference($userid, 'scorm_report_interactions_result', true);
    }
213680
public function updateUserContext(UserContext $context): void
    {
        if ($this->session->isStarted()) {
            $context->addParameter('sessionId', $this->session->getId());
        }
    }
29521
protected static function export_user_devices(int $userid, \context $context) {
        global $DB;
        $records = $DB->get_records('user_devices', ['userid' => $userid]);
        if (!empty($records)) {
            $userdevices = (object) array_map(function($record) {
                return [
                    'appid' => $record->appid,
                    'name' => $record->name,
                    'model' => $record->model,
                    'platform' => $record->platform,
                    'version' => $record->version,
                    'timecreated' => transform::datetime($record->timecreated),
                    'timemodified' => transform::datetime($record->timemodified)
                ];
            }, $records);
            writer::with_context($context)->export_data([get_string('privacy:devicespath', 'user')], $userdevices);
        }
    }
132745
public static function export_user_preferences(int $userid) {
        $draweropennavpref = get_user_preferences(self::DRAWER_OPEN_NAV, null, $userid);

        if (isset($draweropennavpref)) {
            $preferencestring = get_string('privacy:drawernavclosed', 'theme_boost');
            if ($draweropennavpref == 'true') {
                $preferencestring = get_string('privacy:drawernavopen', 'theme_boost');
            }
            \core_privacy\local\request\writer::export_user_preference(
                'theme_boost',
                self::DRAWER_OPEN_NAV,
                $draweropennavpref,
                $preferencestring
            );
        }
    }
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);
    }
86424
public static function get_contexts_for_userid(int $userid) : \core_privacy\local\request\contextlist {
        // We cannot associate files with a particular user as it would require to know all the details about
        // the source file, which only the component owning it knows about. And, the 'usermodified' attribute
        // of the conversion class is not an identifier of data ownership, merely that this user was logged in
        // when the conversion was requested. As such, as the owning component should declare the source file,
        // and we can't make sense of 'usermodified', we will not be reporting anything here. Also note that
        // the clean up task will ensure that whenever a source file is delete, its conversions also are.
        return new \core_privacy\local\request\contextlist();
    }
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')]
                );
            }
        }
    }
597097
public static function export_user_data(approved_contextlist $contextlist) {
        foreach ($contextlist->get_contexts() as $context) {
            // Check that the context is a module context.
            if ($context->contextlevel != CONTEXT_MODULE) {
                continue;
            }
            $user = $contextlist->get_user();
            $assigndata = helper::get_context_data($context, $user);
            helper::export_context_files($context, $user);

            writer::with_context($context)->export_data([], $assigndata);
            $assign = new \assign($context, null, null);

            // I need to find out if I'm a student or a teacher.
            if ($userids = self::get_graded_users($user->id, $assign)) {
                // Return teacher info.
                $currentpath = [get_string('privacy:studentpath', 'mod_assign')];
                foreach ($userids as $studentuserid) {
                    $studentpath = array_merge($currentpath, [$studentuserid->id]);
                    static::export_submission($assign, $studentuserid, $context, $studentpath, true);
                }
            }

            static::export_overrides($context, $assign, $user);
            static::export_submission($assign, $user, $context, []);
            // Meta data.
            self::store_assign_user_flags($context, $assign, $user->id);
            if ($assign->is_blind_marking()) {
                $uniqueid = $assign->get_uniqueid_for_user_static($assign->get_instance()->id, $contextlist->get_user()->id);
                if ($uniqueid) {
                    writer::with_context($context)
                            ->export_metadata([get_string('blindmarking', 'mod_assign')], 'blindmarkingid', $uniqueid,
                                    get_string('privacy:blindmarkingidentifier', 'mod_assign'));
                }
            }
        }
    }
390858
protected static function export_recentitems(int $userid, \context $context) {
        global $DB;
        $sql = "SELECT ra.id, c.fullname, ra.timeaccess, m.name, ra.cmid
                  FROM {block_recentlyaccesseditems} ra
                  JOIN {course} c ON c.id = ra.courseid
                  JOIN {course_modules} cm on cm.id = ra.cmid
                  JOIN {modules} m ON m.id = cm.module
                 WHERE ra.userid = :userid";

        $params = ['userid' => $userid];
        $records = $DB->get_records_sql($sql, $params);
        if (!empty($records)) {
            $recentitems = (object) array_map(function($record) use($context) {
                return [
                        'course_name' => format_string($record->fullname, true, ['context' => $context]),
                        'module_name' => format_string($record->name),
                        'timeaccess' => transform::datetime($record->timeaccess)
                ];
            }, $records);
            writer::with_context($context)->export_data([get_string('privacy:recentlyaccesseditemspath',
                    'block_recentlyaccesseditems')], $recentitems);
        }
    }
1145764
public static function delete_data_for_all_users_in_context(\context $context) {
        global $DB;

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

        // Delete the repository_instances records created for the userid.
        $DB->delete_records('repository_instances', ['userid' => $userid]);
    }
956978
protected static function export_course_requests(int $userid, \context $context) {
        global $DB;
        $sql = "SELECT cr.shortname, cr.fullname, cr.summary, cc.name AS category, cr.reason
                  FROM {course_request} cr
                  JOIN {course_categories} cc ON cr.category = cc.id
                 WHERE cr.requester = :userid";
        $params = ['userid' => $userid];
        $records = $DB->get_records_sql($sql, $params);
        if ($records) {
            writer::with_context($context)->export_data([get_string('privacy:courserequestpath', 'user')], (object) $records);
        }
    }
216362
protected static function export_user_data_contact_requests(int $userid) {
        global $DB;

        $context = \context_user::instance($userid);

        if ($contactrequests = $DB->get_records_select('message_contact_requests', 'userid = ? OR requesteduserid = ?',
                [$userid, $userid], 'id ASC')) {
            $contactrequestsdata = [];
            foreach ($contactrequests as $contactrequest) {
                if ($userid == $contactrequest->requesteduserid) {
                    $maderequest = false;
                    $contactid = $contactrequest->userid;
                } else {
                    $maderequest = true;
                    $contactid = $contactrequest->requesteduserid;
                }

                $contactrequestsdata[] = (object) [
                    'contactrequest' => transform::user($contactid),
                    'maderequest' => transform::yesno($maderequest)
                ];
            }
            writer::with_context($context)->export_data([get_string('contactrequests', 'core_message')],
                (object) $contactrequestsdata);
        }
    }