Your IP : 216.73.216.95


Current Path : /var/www/ljmtc/cbt/mod/grouptool/classes/privacy/
Upload File :
Current File : /var/www/ljmtc/cbt/mod/grouptool/classes/privacy/provider.php

<?php
// This file is part of mod_grouptool for Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Privacy class for requesting user data.
 *
 * @package    mod_grouptool
 * @author     Philipp Hager
 * @copyright  2018 Academic Moodle Cooperation {@link http://www.academic-moodle-cooperation.org}
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
namespace mod_grouptool\privacy;

use core_privacy\local\metadata\collection;
use core_privacy\local\metadata\provider as metadataprovider;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\plugin\provider as pluginprovider;
use core_privacy\local\request\user_preference_provider as preference_provider;
use core_privacy\local\request\writer;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\helper;
use core_privacy\local\request\core_userlist_provider;
use core_privacy\local\request\userlist;
use core_privacy\local\request\approved_userlist;

defined('MOODLE_INTERNAL') || die();

// Global variable $CFG is always set, but with this little wrapper PHPStorm won't give wrong error messages!
if (isset($CFG)) {
    require_once($CFG->dirroot . '/mod/grouptool/locallib.php');
}

/**
 * Privacy class for requesting user data.
 *
 * @package    mod_grouptool
 * @author     Philipp Hager
 * @copyright  2018 Academic Moodle Cooperation {@link http://www.academic-moodle-cooperation.org}
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
class provider implements metadataprovider, pluginprovider, preference_provider, core_userlist_provider {
    /**
     * Provides meta data that is stored about a user with mod_publication
     *
     * @param  collection $collection A collection of meta data items to be added to.
     * @return  collection Returns the collection of metadata.
     */
    public static function get_metadata(collection $collection): collection {
        $queued = [
                'agrpid' => 'privacy:metadata:agrpid',
                'userid' => 'privacy:metadata:userid',
                'timestamp' => 'privacy:metadata:timestamp'
        ];

        $registered = [
                'agrpid' => 'privacy:metadata:agrpid',
                'userid' => 'privacy:metadata:userid',
                'timestamp' => 'privacy:metadata:timestamp',
                'modified_by' => 'privacy:metadata:modified_by'
        ];

        $collection->add_database_table('grouptool_queued', $queued, 'privacy:metadata:queued');
        $collection->add_database_table('grouptool_registered', $registered, 'privacy:metadata:registered');

        $collection->add_user_preference('mod_grouptool_group_filter', 'privacy:metadata:mod_grouptool_group_filter');
        $collection->add_user_preference('mod_grouptool_mygroups_only', 'privacy:metadata:mod_grouptool_mygroups_only');

        // Link to subplugins.
        $collection->add_subsystem_link('core_enrol', [], 'privacy:metadata:enrolexplanation');
        $collection->add_subsystem_link('core_grades', [], 'privacy:metadata:gradesexplanation');
        $collection->add_subsystem_link('core_group', [], 'privacy:metadata:groupexplanation');
        $collection->add_subsystem_link('core_message', [], 'privacy:metadata:messageexplanation');

        return $collection;
    }

    /**
     * Returns all of the contexts that has information relating to the userid.
     *
     * @param  int $userid The user ID.
     * @return contextlist an object with the contexts related to a userid.
     */
    public static function get_contexts_for_userid(int $userid): contextlist {
        $params = [
                'modulename' => 'grouptool',
                'contextlevel' => CONTEXT_MODULE,
                'queueuserid' => $userid,
                'reguserid' => $userid,
                'regmodifierid' => $userid
        ];

        $sql = "SELECT ctx.id
                  FROM {course_modules} cm
                  JOIN {modules} m ON cm.module = m.id AND m.name = :modulename
                  JOIN {grouptool} g ON cm.instance = g.id
                  JOIN {context} ctx ON cm.id = ctx.instanceid AND ctx.contextlevel = :contextlevel
             LEFT JOIN {grouptool_agrps} agrp ON g.id = agrp.grouptoolid
             LEFT JOIN {grouptool_registered} r ON r.agrpid = agrp.id
             LEFT JOIN {grouptool_queued} q ON q.agrpid = agrp.id
                 WHERE r.userid = :reguserid OR q.userid = :queueuserid OR r.modified_by = :regmodifierid";
        $contextlist = new contextlist();

        $contextlist->add_from_sql($sql, $params);

        return $contextlist;
    }

    /**
     * Get the list of users who have data within a context.
     *
     * @param   userlist    $userlist   The userlist containing the list of users who have data in this context/plugin combination.
     */
    public static function get_users_in_context(userlist $userlist) {
        $context = $userlist->get_context();

        if ($context->contextlevel != CONTEXT_MODULE) {
            return;
        }

        $params = [
                'modulename' => 'grouptool',
                'contextid' => $context->id,
                'contextlevel' => CONTEXT_MODULE
        ];

        // Get all who are queued or registered or marked or have modified, but only real users, no empty values!
        foreach (['grouptool_queued' => ['userid'],
                  'grouptool_registered' => ['userid', 'modified_by']] as $table => $fields) {
            foreach ($fields as $field) {
                $sql = "SELECT r." . $field . "
                          FROM {context} ctx
                          JOIN {course_modules} cm ON cm.id = ctx.instanceid
                          JOIN {modules} m ON m.id = cm.module AND m.name = :modulename
                          JOIN {grouptool} g ON g.id = cm.instance
                          JOIN {grouptool_agrps} a ON g.id = a.grouptoolid
                          JOIN {" . $table . "} r ON a.id = r.agrpid
                         WHERE ctx.id = :contextid AND ctx.contextlevel = :contextlevel AND r." . $field . " > 0";
                $userlist->add_from_sql($field, $sql, $params);
            }
        }
    }

    /**
     * Delete multiple users within a single context.
     *
     * @param   approved_userlist       $userlist The approved context and user information to delete information for.
     */
    public static function delete_data_for_users(approved_userlist $userlist) {
        global $DB;

        $context = $userlist->get_context();

        if ($context->contextlevel == CONTEXT_MODULE) {
            // Apparently we can't trust anything that comes via the context.
            // Go go mega query to find out it we have an checkmark context that matches an existing checkmark.
            $sql = "SELECT g.*
                    FROM {grouptool} g
                    JOIN {course_modules} cm ON g.id = cm.instance AND g.course = cm.course
                    JOIN {modules} m ON m.id = cm.module AND m.name = :modulename
                    JOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :contextmodule
                    WHERE ctx.id = :contextid";
            $params = ['modulename' => 'grouptool', 'contextmodule' => CONTEXT_MODULE, 'contextid' => $context->id];
            $grouptool = $DB->get_record_sql($sql, $params);
            // If we have an id over zero then we can proceed.
            if (!empty($grouptool) && $grouptool->id > 0) {
                $userids = $userlist->get_userids();
                if (count($userids) <= 0) {
                    return;
                }

                $cm = get_coursemodule_from_instance('grouptool', $grouptool->id);

                $agrpids = $DB->get_fieldset_select('grouptool_agrps', 'id', 'grouptoolid = ?', [$grouptool->id]);
                list($agrpsql, $agrpparams) = $DB->get_in_or_equal($agrpids, SQL_PARAMS_NAMED, 'agrp');

                list($usersql, $userparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED, 'usr');

                $DB->delete_records_select('grouptool_registered', "agrpid ".$agrpsql." AND userid ".$usersql,
                        $agrpparams + $userparams);
                $DB->delete_records_select('grouptool_queued', "agrpid ".$agrpsql." AND userid ".$usersql,
                        $agrpparams + $userparams);
                $instance = new \mod_grouptool($cm->id, $grouptool, $cm);
                foreach ($agrpids as $cur) {
                    $instance->fill_from_queue($cur);
                }
            }
        }
    }


    /**
     * Write out the user data filtered by contexts.
     *
     *
     * @param approved_contextlist $contextlist contexts that we are writing data out from.
     * @throws \coding_exception
     * @throws \dml_exception
     * @throws \moodle_exception
     */
    public static function export_user_data(approved_contextlist $contextlist) {
        global $DB;

        $contexts = $contextlist->get_contexts();

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

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

        $sql = "SELECT
                    c.id AS contextid,
                    g.*,
                    cm.id AS cmid
                  FROM {context} c
                  JOIN {course_modules} cm ON cm.id = c.instanceid
                  JOIN {grouptool} g ON g.id = cm.instance
                 WHERE c.id {$contextsql}";

        // Keep a mapping of grouptoolid to contextid.
        $mappings = [];

        $grouptools = $DB->get_records_sql($sql, $contextparams);

        $user = $contextlist->get_user();

        foreach ($grouptools as $grouptool) {
            $context = \context_module::instance($grouptool->cmid);
            $mappings[$grouptool->id] = $grouptool->contextid;

            // Check that the context is a module context.
            if ($context->contextlevel != CONTEXT_MODULE) {
                continue;
            }

            $grouptooldata = helper::get_context_data($context, $user);
            helper::export_context_files($context, $user);

            $cm = get_coursemodule_from_instance('grouptool', $grouptool->id);

            $course = $DB->get_record('course', ['id' => $cm->course], '*', MUST_EXIST);
            $grouptool = new \mod_grouptool($cm->id, $grouptool, $cm, $course);

            writer::with_context($context)->export_data([], $grouptooldata);

            /* We don't differentiate between roles, if we have data about the user, we give it freely ;) - no sensible
             * information here! */

            static::export_user_preferences($user->id);
            static::export_regs($context, $grouptool, $user);
        }
    }

    /**
     * Stores the user preferences related to mod_publication.
     *
     * @param  int $userid The user ID that we want the preferences for.
     * @throws \dml_exception
     * @throws \coding_exception
     */
    public static function export_user_preferences(int $userid) {
        $context = \context_system::instance();

        $preferences = [
            'mod_grouptool_group_filter',
            'mod_grouptool_mygroups_only'
        ];

        foreach ($preferences as $cur) {
            $value = get_user_preferences($cur, null, $userid);
            if ($value !== null) {
                writer::with_context($context)->export_user_preference('mod_grouptool', $cur, $value,
                        get_string('privacy:metadata:' . $cur, 'mod_grouptool'));
            }
        }
    }

    /**
     * Export overrides for this grouptool.
     *
     * @param  \context $context Context
     * @param  \mod_grouptool $grouptool The publication object.
     * @param  \stdClass $user The user object.
     * @throws \coding_exception
     * @throws \dml_exception
     */
    public static function export_regs(\context $context, \mod_grouptool $grouptool, \stdClass $user) {
        global $DB;

        // Get all active groups including inactive indexed by agrpid!
        $agrps = $DB->get_records_sql("SELECT agrp.*, g.name
                                         FROM {grouptool_agrps} agrp
                                         JOIN {groups} g ON g.id = agrp.groupid
                                         WHERE agrp.grouptoolid = :grouptoolid", ['grouptoolid' => $grouptool->get_settings()->id]);

        list($agrpssql, $agrpsparams) = $DB->get_in_or_equal(array_keys($agrps), SQL_PARAMS_NAMED);
        $sql = "userid = :userid AND agrpid ".$agrpssql;
        $queues = $DB->get_records_select('grouptool_queued', $sql, ['userid' => $user->id] + $agrpsparams);
        $sql = "(userid = :userid OR modified_by = :modifierid) AND agrpid ".$agrpssql;
        $regs = $DB->get_records_select('grouptool_registered', $sql,
                ['userid' => $user->id, 'modifierid' => $user->id] + $agrpsparams);

        $export = new \stdClass();
        $strmarked = get_string('grp_marked', 'grouptool');
        $strregistered = get_string('registered', 'grouptool');
        $strqueued = get_string('queued', 'grouptool');
        if (!empty($regs)) {
            foreach ($regs as $cur) {
                $tmp = [
                        'group' => $agrps[$cur->agrpid]->name,
                        'status' => ($cur->modified_by === -1) ? $strmarked : $strregistered,
                        'timestamp' => transform::datetime($cur->timestamp)
                ];
                if ($cur->userid != $user->id) {
                    if (!isset($export->modified)) {
                        $export->modified = [];
                    }
                    $export->modified[] = $tmp;
                } else {
                    if ($cur->modified_by !== -1) {
                        if (!isset($export->registrations)) {
                            $export->registrations = [];
                        }
                        $export->registrations[] = $tmp;
                    } else {
                        if (!isset($export->marks)) {
                            $export->marks = [];
                        }
                        $export->marks[] = $tmp;
                    }
                }
            }
        }
        if (!empty($queues)) {
            $export->queues = [];
            foreach ($queues as $cur) {
                $export->queues[] = [
                        'group' => $agrps[$cur->agrpid]->name,
                        'status' => $strqueued,
                        'timestamp' => transform::datetime($cur->timestamp)
                ];
            }
        }
        writer::with_context($context)->export_data([], $export);
    }

    /**
     * Delete all use data which matches the specified context.
     *
     * @param \context $context The module context.
     * @throws \dml_exception
     */
    public static function delete_data_for_all_users_in_context(\context $context) {
        global $DB;

        if ($context->contextlevel == CONTEXT_MODULE) {
            // Apparently we can't trust anything that comes via the context.
            // Go go mega query to find out it we have an assign context that matches an existing assignment.
            $sql = "SELECT g.id
                    FROM {grouptool} g
                    JOIN {course_modules} cm ON g.id = cm.instance AND g.course = cm.course
                    JOIN {modules} m ON m.id = cm.module AND m.name = :modulename
                    JOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :contextmodule
                    WHERE ctx.id = :contextid";
            $params = ['modulename' => 'grouptool', 'contextmodule' => CONTEXT_MODULE, 'contextid' => $context->id];
            $id = $DB->get_field_sql($sql, $params);
            // If we have a count over zero then we can proceed.
            if ($id > 0) {
                $agrps = $DB->get_fieldset_select('grouptool_agrps', 'id', 'grouptoolid = :grouptoolid', ['grouptoolid' => $id]);

                // Get all grouptool regs and queues to delete them!
                $DB->delete_records_list('grouptool_registered', 'agrpid', $agrps);
                $DB->delete_records_list('grouptool_queued', 'agrpid', $agrps);
            }
        }
    }

    /**
     * Delete all user data for the specified user, in the specified contexts.
     *
     * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
     * @throws \dml_exception
     * @throws \coding_exception
     */
    public static function delete_data_for_user(approved_contextlist $contextlist) {
        global $DB;

        $user = $contextlist->get_user();

        $contextids = $contextlist->get_contextids();

        if (empty($contextids) || $contextids === []) {
            return;
        }

        list($ctxsql, $ctxparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED, 'ctx');

        // Apparently we can't trust anything that comes via the context.
        // Go go mega query to find out it we have an grouptool context that matches an existing grouptool.
        $sql = "SELECT ctx.id AS ctxid, g.*
                    FROM {grouptool} g
                    JOIN {course_modules} cm ON g.id = cm.instance AND g.course = cm.course
                    JOIN {modules} m ON m.id = cm.module AND m.name = :modulename
                    JOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :contextmodule
                    WHERE ctx.id ".$ctxsql;
        $params = ['modulename' => 'grouptool', 'contextmodule' => CONTEXT_MODULE];

        if (!$records = $DB->get_records_sql($sql, $params + $ctxparams)) {
            return;
        }
        $grouptoolids = [];
        foreach ($contextlist as $context) {
            if ($context->contextlevel != CONTEXT_MODULE) {
                continue;
            }

            $grouptoolids[] = $records[$context->id]->id;
        }

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

        list($select, $params) = $DB->get_in_or_equal($grouptoolids);
        $agrpids = $DB->get_fieldset_select('grouptool_agrps', 'id', 'grouptoolid '.$select, $params);

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

        list($agrpssql, $agrpparams) = $DB->get_in_or_equal($agrpids, SQL_PARAMS_NAMED);
        $DB->delete_records_select('grouptool_registered',
                "(userid = :userid OR modified_by = :modifierid) AND agrpid ".$agrpssql,
                $agrpparams + ['userid' => $user->id, 'modifierid' => $user->id]);
        $DB->delete_records_select('grouptool_queued', "userid = :userid AND agrpid ".$agrpssql,
                $agrpparams + ['userid' => $user->id]);

        $grouptools = $DB->get_records_list('grouptool', 'id', $grouptoolids);
        foreach ($grouptools as $cur) {
            $cm = get_coursemodule_from_instance('grouptool', $cur->id);
            $grouptool = new \mod_grouptool($cm->id, $cur, $cm);
            $gtagrps = array_keys($grouptool->get_active_groups(false, false, 0, 0, 0, false));
            foreach (array_intersect($agrpids, $gtagrps) as $agrpid) {
                $grouptool->fill_from_queue($agrpid);
            }
        }
    }
}