| 1 | efrain | 1 | <?php
 | 
        
           |  |  | 2 | // This file is part of Moodle - http://moodle.org/
 | 
        
           |  |  | 3 | //
 | 
        
           |  |  | 4 | // Moodle is free software: you can redistribute it and/or modify
 | 
        
           |  |  | 5 | // it under the terms of the GNU General Public License as published by
 | 
        
           |  |  | 6 | // the Free Software Foundation, either version 3 of the License, or
 | 
        
           |  |  | 7 | // (at your option) any later version.
 | 
        
           |  |  | 8 | //
 | 
        
           |  |  | 9 | // Moodle is distributed in the hope that it will be useful,
 | 
        
           |  |  | 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
        
           |  |  | 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
        
           |  |  | 12 | // GNU General Public License for more details.
 | 
        
           |  |  | 13 | //
 | 
        
           |  |  | 14 | // You should have received a copy of the GNU General Public License
 | 
        
           |  |  | 15 | // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 | 
        
           |  |  | 16 | /**
 | 
        
           |  |  | 17 |  * Privacy Subsystem implementation for core_mnet.
 | 
        
           |  |  | 18 |  *
 | 
        
           |  |  | 19 |  * @package    core_mnet
 | 
        
           |  |  | 20 |  * @copyright  2018 Carlos Escobedo <carlos@moodle.com>
 | 
        
           |  |  | 21 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 22 |  */
 | 
        
           |  |  | 23 | namespace core_mnet\privacy;
 | 
        
           |  |  | 24 | defined('MOODLE_INTERNAL') || die();
 | 
        
           | 1441 | ariadna | 25 |   | 
        
           |  |  | 26 | use core_privacy\local\metadata\collection;
 | 
        
           |  |  | 27 | use core_privacy\local\request\contextlist;
 | 
        
           |  |  | 28 | use core_privacy\local\request\approved_contextlist;
 | 
        
           |  |  | 29 | use core_privacy\local\request\transform;
 | 
        
           |  |  | 30 | use core_privacy\local\request\writer;
 | 
        
           |  |  | 31 | use core_privacy\local\request\userlist;
 | 
        
           |  |  | 32 | use core_privacy\local\request\approved_userlist;
 | 
        
           |  |  | 33 |   | 
        
           | 1 | efrain | 34 | /**
 | 
        
           |  |  | 35 |  * Privacy Subsystem for core_mnet implementing null_provider.
 | 
        
           |  |  | 36 |  *
 | 
        
           |  |  | 37 |  * @copyright  2018 Carlos Escobedo <carlos@moodle.com>
 | 
        
           |  |  | 38 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 39 |  */
 | 
        
           | 1441 | ariadna | 40 | class provider implements
 | 
        
           |  |  | 41 |     \core_privacy\local\metadata\provider,
 | 
        
           |  |  | 42 |     \core_privacy\local\request\core_userlist_provider,
 | 
        
           |  |  | 43 |     \core_privacy\local\request\subsystem\provider {
 | 
        
           | 1 | efrain | 44 |     /**
 | 
        
           | 1441 | ariadna | 45 |      * Returns meta data about this system.
 | 
        
           | 1 | efrain | 46 |      *
 | 
        
           | 1441 | ariadna | 47 |      * @param   collection $collection The initialised item collection to add items to.
 | 
        
           |  |  | 48 |      * @return  collection     A listing of user data stored through this system.
 | 
        
           | 1 | efrain | 49 |      */
 | 
        
           | 1441 | ariadna | 50 |     public static function get_metadata(collection $collection): collection {
 | 
        
           |  |  | 51 |   | 
        
           |  |  | 52 |         $sessionfields = [
 | 
        
           |  |  | 53 |                 'userid' => 'privacy:metadata:mnet_session:userid',
 | 
        
           |  |  | 54 |                 'username' => 'privacy:metadata:mnet_session:username',
 | 
        
           |  |  | 55 |                 'token' => 'privacy:metadata:mnet_session:token',
 | 
        
           |  |  | 56 |                 'mnethostid' => 'privacy:metadata:mnet_session:mnethostid',
 | 
        
           |  |  | 57 |                 'useragent' => 'privacy:metadata:mnet_session:useragent',
 | 
        
           |  |  | 58 |                 'expires' => 'privacy:metadata:mnet_session:expires',
 | 
        
           |  |  | 59 |         ];
 | 
        
           |  |  | 60 |   | 
        
           |  |  | 61 |         $collection->add_database_table('mnet_session', $sessionfields, 'privacy:metadata:mnet_session');
 | 
        
           |  |  | 62 |   | 
        
           |  |  | 63 |         $logfields = [
 | 
        
           |  |  | 64 |                 'hostid' => 'privacy:metadata:mnet_log:hostid',
 | 
        
           |  |  | 65 |                 'remoteid' => 'privacy:metadata:mnet_log:remoteid',
 | 
        
           |  |  | 66 |                 'time' => 'privacy:metadata:mnet_log:time',
 | 
        
           |  |  | 67 |                 'userid' => 'privacy:metadata:mnet_log:userid',
 | 
        
           |  |  | 68 |                 'ip' => 'privacy:metadata:mnet_log:ip',
 | 
        
           |  |  | 69 |                 'course' => 'privacy:metadata:mnet_log:course',
 | 
        
           |  |  | 70 |                 'coursename' => 'privacy:metadata:mnet_log:coursename',
 | 
        
           |  |  | 71 |                 'module' => 'privacy:metadata:mnet_log:module',
 | 
        
           |  |  | 72 |                 'cmid' => 'privacy:metadata:mnet_log:cmid',
 | 
        
           |  |  | 73 |                 'action' => 'privacy:metadata:mnet_log:action',
 | 
        
           |  |  | 74 |                 'url' => 'privacy:metadata:mnet_log:url',
 | 
        
           |  |  | 75 |                 'info' => 'privacy:metadata:mnet_log:info',
 | 
        
           |  |  | 76 |         ];
 | 
        
           |  |  | 77 |   | 
        
           |  |  | 78 |         $collection->add_database_table('mnet_log', $logfields, 'privacy:metadata:mnet_log');
 | 
        
           |  |  | 79 |   | 
        
           |  |  | 80 |         $externalfields = [
 | 
        
           |  |  | 81 |                 'address' => 'privacy:metadata:mnet_external:address',
 | 
        
           |  |  | 82 |                 'alternatename' => 'privacy:metadata:mnet_external:alternatename',
 | 
        
           |  |  | 83 |                 'autosubscribe' => 'privacy:metadata:mnet_external:autosubscribe',
 | 
        
           |  |  | 84 |                 'calendartype' => 'privacy:metadata:mnet_external:calendartype',
 | 
        
           |  |  | 85 |                 'city' => 'privacy:metadata:mnet_external:city',
 | 
        
           |  |  | 86 |                 'country' => 'privacy:metadata:mnet_external:country',
 | 
        
           |  |  | 87 |                 'currentlogin' => 'privacy:metadata:mnet_external:currentlogin',
 | 
        
           |  |  | 88 |                 'department' => 'privacy:metadata:mnet_external:department',
 | 
        
           |  |  | 89 |                 'description' => 'privacy:metadata:mnet_external:description',
 | 
        
           |  |  | 90 |                 'email' => 'privacy:metadata:mnet_external:email',
 | 
        
           |  |  | 91 |                 'emailstop' => 'privacy:metadata:mnet_external:emailstop',
 | 
        
           |  |  | 92 |                 'firstaccess' => 'privacy:metadata:mnet_external:firstaccess',
 | 
        
           |  |  | 93 |                 'firstname' => 'privacy:metadata:mnet_external:firstname',
 | 
        
           |  |  | 94 |                 'firstnamephonetic' => 'privacy:metadata:mnet_external:firstnamephonetic',
 | 
        
           |  |  | 95 |                 'id' => 'privacy:metadata:mnet_external:id',
 | 
        
           |  |  | 96 |                 'idnumber' => 'privacy:metadata:mnet_external:idnumber',
 | 
        
           |  |  | 97 |                 'imagealt' => 'privacy:metadata:mnet_external:imagealt',
 | 
        
           |  |  | 98 |                 'institution' => 'privacy:metadata:mnet_external:institution',
 | 
        
           |  |  | 99 |                 'lang' => 'privacy:metadata:mnet_external:lang',
 | 
        
           |  |  | 100 |                 'lastaccess' => 'privacy:metadata:mnet_external:lastaccess',
 | 
        
           |  |  | 101 |                 'lastlogin' => 'privacy:metadata:mnet_external:lastlogin',
 | 
        
           |  |  | 102 |                 'lastname' => 'privacy:metadata:mnet_external:lastname',
 | 
        
           |  |  | 103 |                 'lastnamephonetic' => 'privacy:metadata:mnet_external:lastnamephonetic',
 | 
        
           |  |  | 104 |                 'maildigest' => 'privacy:metadata:mnet_external:maildigest',
 | 
        
           |  |  | 105 |                 'maildisplay' => 'privacy:metadata:mnet_external:maildisplay',
 | 
        
           |  |  | 106 |                 'middlename' => 'privacy:metadata:mnet_external:middlename',
 | 
        
           |  |  | 107 |                 'phone1' => 'privacy:metadata:mnet_external:phone1',
 | 
        
           |  |  | 108 |                 'pnone2' => 'privacy:metadata:mnet_external:phone2',
 | 
        
           |  |  | 109 |                 'picture' => 'privacy:metadata:mnet_external:picture',
 | 
        
           |  |  | 110 |                 'policyagreed' => 'privacy:metadata:mnet_external:policyagreed',
 | 
        
           |  |  | 111 |                 'suspended' => 'privacy:metadata:mnet_external:suspended',
 | 
        
           |  |  | 112 |                 'timezone' => 'privacy:metadata:mnet_external:timezone',
 | 
        
           |  |  | 113 |                 'trackforums' => 'privacy:metadata:mnet_external:trackforums',
 | 
        
           |  |  | 114 |                 'trustbitmask' => 'privacy:metadata:mnet_external:trustbitmask',
 | 
        
           |  |  | 115 |                 'username' => 'privacy:metadata:mnet_external:username',
 | 
        
           |  |  | 116 |         ];
 | 
        
           |  |  | 117 |   | 
        
           |  |  | 118 |         $collection->add_external_location_link('moodle', $externalfields, 'privacy:metadata:external:moodle');
 | 
        
           |  |  | 119 |   | 
        
           |  |  | 120 |         $collection->add_external_location_link('mahara', $externalfields, 'privacy:metadata:external:mahara');
 | 
        
           |  |  | 121 |   | 
        
           |  |  | 122 |         return $collection;
 | 
        
           | 1 | efrain | 123 |     }
 | 
        
           | 1441 | ariadna | 124 |   | 
        
           |  |  | 125 |     /**
 | 
        
           |  |  | 126 |      * Get the list of contexts that contain user information for the specified user.
 | 
        
           |  |  | 127 |      *
 | 
        
           |  |  | 128 |      * @param   int $userid The user to search.
 | 
        
           |  |  | 129 |      * @return  contextlist   $contextlist  The list of contexts used in this plugin.
 | 
        
           |  |  | 130 |      */
 | 
        
           |  |  | 131 |     public static function get_contexts_for_userid(int $userid): contextlist {
 | 
        
           |  |  | 132 |         $sql = "SELECT ctx.id
 | 
        
           |  |  | 133 |                   FROM {mnet_log} ml
 | 
        
           |  |  | 134 |                   JOIN {context} ctx ON ctx.instanceid = ml.userid AND ctx.contextlevel = :contextlevel
 | 
        
           |  |  | 135 |                  WHERE ml.userid = :userid";
 | 
        
           |  |  | 136 |         $params = ['userid' => $userid, 'contextlevel' => CONTEXT_USER];
 | 
        
           |  |  | 137 |   | 
        
           |  |  | 138 |         $contextlist = new contextlist();
 | 
        
           |  |  | 139 |         $contextlist->add_from_sql($sql, $params);
 | 
        
           |  |  | 140 |   | 
        
           |  |  | 141 |         return $contextlist;
 | 
        
           |  |  | 142 |     }
 | 
        
           |  |  | 143 |   | 
        
           |  |  | 144 |     /**
 | 
        
           |  |  | 145 |      * Get the list of users within a specific context.
 | 
        
           |  |  | 146 |      *
 | 
        
           |  |  | 147 |      * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
 | 
        
           |  |  | 148 |      */
 | 
        
           |  |  | 149 |     public static function get_users_in_context(userlist $userlist): void {
 | 
        
           |  |  | 150 |         $context = $userlist->get_context();
 | 
        
           |  |  | 151 |   | 
        
           |  |  | 152 |         if (!$context instanceof \context_user) {
 | 
        
           |  |  | 153 |             return;
 | 
        
           |  |  | 154 |         }
 | 
        
           |  |  | 155 |   | 
        
           |  |  | 156 |         $sql = "SELECT userid
 | 
        
           |  |  | 157 |                   FROM {mnet_log}
 | 
        
           |  |  | 158 |                  WHERE userid = ?";
 | 
        
           |  |  | 159 |         $params = [$context->instanceid];
 | 
        
           |  |  | 160 |         $userlist->add_from_sql('userid', $sql, $params);
 | 
        
           |  |  | 161 |     }
 | 
        
           |  |  | 162 |   | 
        
           |  |  | 163 |     /**
 | 
        
           |  |  | 164 |      * Export all user data for the specified user, in the specified contexts, using the supplied exporter instance.
 | 
        
           |  |  | 165 |      *
 | 
        
           |  |  | 166 |      * @param   approved_contextlist $contextlist The approved contexts to export information for.
 | 
        
           |  |  | 167 |      */
 | 
        
           |  |  | 168 |     public static function export_user_data(approved_contextlist $contextlist): void {
 | 
        
           |  |  | 169 |         global $DB;
 | 
        
           |  |  | 170 |   | 
        
           |  |  | 171 |         $context = \context_user::instance($contextlist->get_user()->id);
 | 
        
           |  |  | 172 |   | 
        
           |  |  | 173 |         $sql = "SELECT ml.id, mh.wwwroot, mh.name, ml.remoteid, ml.time, ml.userid, ml.ip, ml.course,
 | 
        
           |  |  | 174 |                        ml.coursename, ml.module, ml.cmid, ml.action, ml.url, ml.info
 | 
        
           |  |  | 175 |                   FROM {mnet_log} ml
 | 
        
           |  |  | 176 |                   JOIN {mnet_host} mh ON mh.id = ml.hostid
 | 
        
           |  |  | 177 |                  WHERE ml.userid = :userid
 | 
        
           |  |  | 178 |               ORDER BY mh.name, ml.coursename";
 | 
        
           |  |  | 179 |         $params = ['userid' => $contextlist->get_user()->id];
 | 
        
           |  |  | 180 |   | 
        
           |  |  | 181 |         $data = [];
 | 
        
           |  |  | 182 |         $lastcourseid = null;
 | 
        
           |  |  | 183 |   | 
        
           |  |  | 184 |         $logentries = $DB->get_recordset_sql($sql, $params);
 | 
        
           |  |  | 185 |         foreach ($logentries as $logentry) {
 | 
        
           |  |  | 186 |             $item = (object) [
 | 
        
           |  |  | 187 |                     'time' => transform::datetime($logentry->time),
 | 
        
           |  |  | 188 |                     'remoteid' => $logentry->remoteid,
 | 
        
           |  |  | 189 |                     'ip' => $logentry->ip,
 | 
        
           |  |  | 190 |                     'course' => $logentry->course,
 | 
        
           |  |  | 191 |                     'coursename' => format_string($logentry->coursename),
 | 
        
           |  |  | 192 |                     'module' => $logentry->module,
 | 
        
           |  |  | 193 |                     'cmid' => $logentry->cmid,
 | 
        
           |  |  | 194 |                     'action' => $logentry->action,
 | 
        
           |  |  | 195 |                     'url' => $logentry->url,
 | 
        
           |  |  | 196 |                     'info' => format_string($logentry->info),
 | 
        
           |  |  | 197 |             ];
 | 
        
           |  |  | 198 |   | 
        
           |  |  | 199 |             $item->externalhost =
 | 
        
           |  |  | 200 |                     ($logentry->name == '') ? preg_replace('#^https?://#', '', $logentry->wwwroot) :
 | 
        
           |  |  | 201 |                             preg_replace('#^https?://#', '', $logentry->name);
 | 
        
           |  |  | 202 |   | 
        
           |  |  | 203 |             if ($lastcourseid && $lastcourseid != $logentry->course) {
 | 
        
           |  |  | 204 |                 $path = [get_string('mnet', 'core_mnet'), $data[0]->externalhost, $data[0]->coursename];
 | 
        
           |  |  | 205 |                 writer::with_context($context)->export_data($path, (object) $data);
 | 
        
           |  |  | 206 |                 $data = [];
 | 
        
           |  |  | 207 |             }
 | 
        
           |  |  | 208 |   | 
        
           |  |  | 209 |             $data[] = $item;
 | 
        
           |  |  | 210 |             $lastcourseid = $logentry->course;
 | 
        
           |  |  | 211 |         }
 | 
        
           |  |  | 212 |         $logentries->close();
 | 
        
           |  |  | 213 |   | 
        
           |  |  | 214 |         $path = [get_string('mnet', 'core_mnet'), $item->externalhost, $item->coursename];
 | 
        
           |  |  | 215 |         writer::with_context($context)->export_data($path, (object) $data);
 | 
        
           |  |  | 216 |     }
 | 
        
           |  |  | 217 |   | 
        
           |  |  | 218 |     /**
 | 
        
           |  |  | 219 |      * Delete all personal data for all users in the specified context.
 | 
        
           |  |  | 220 |      *
 | 
        
           |  |  | 221 |      * @param \context $context Context to delete data from.
 | 
        
           |  |  | 222 |      */
 | 
        
           |  |  | 223 |     public static function delete_data_for_all_users_in_context(\context $context): void {
 | 
        
           |  |  | 224 |         global $DB;
 | 
        
           |  |  | 225 |   | 
        
           |  |  | 226 |         if ($context->contextlevel != CONTEXT_USER) {
 | 
        
           |  |  | 227 |             return;
 | 
        
           |  |  | 228 |         }
 | 
        
           |  |  | 229 |   | 
        
           |  |  | 230 |         $DB->delete_records('mnet_log', ['userid' => $context->instanceid]);
 | 
        
           |  |  | 231 |     }
 | 
        
           |  |  | 232 |   | 
        
           |  |  | 233 |     /**
 | 
        
           |  |  | 234 |      * Delete multiple users within a single context.
 | 
        
           |  |  | 235 |      *
 | 
        
           |  |  | 236 |      * @param approved_userlist $userlist The approved context and user information to delete information for.
 | 
        
           |  |  | 237 |      */
 | 
        
           |  |  | 238 |     public static function delete_data_for_users(approved_userlist $userlist): void {
 | 
        
           |  |  | 239 |         global $DB;
 | 
        
           |  |  | 240 |   | 
        
           |  |  | 241 |         $context = $userlist->get_context();
 | 
        
           |  |  | 242 |   | 
        
           |  |  | 243 |         if ($context instanceof \context_user) {
 | 
        
           |  |  | 244 |             $DB->delete_records('mnet_log', ['userid' => $context->instanceid]);
 | 
        
           |  |  | 245 |         }
 | 
        
           |  |  | 246 |     }
 | 
        
           |  |  | 247 |   | 
        
           |  |  | 248 |     /**
 | 
        
           |  |  | 249 |      * Delete all user data for the specified user, in the specified contexts.
 | 
        
           |  |  | 250 |      *
 | 
        
           |  |  | 251 |      * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
 | 
        
           |  |  | 252 |      */
 | 
        
           |  |  | 253 |     public static function delete_data_for_user(approved_contextlist $contextlist): void {
 | 
        
           |  |  | 254 |         global $DB;
 | 
        
           |  |  | 255 |   | 
        
           |  |  | 256 |         if (empty($contextlist->count())) {
 | 
        
           |  |  | 257 |             return;
 | 
        
           |  |  | 258 |         }
 | 
        
           |  |  | 259 |   | 
        
           |  |  | 260 |         $userid = $contextlist->get_user()->id;
 | 
        
           |  |  | 261 |         foreach ($contextlist->get_contexts() as $context) {
 | 
        
           |  |  | 262 |             if ($context->contextlevel != CONTEXT_USER) {
 | 
        
           |  |  | 263 |                 continue;
 | 
        
           |  |  | 264 |             }
 | 
        
           |  |  | 265 |             if ($context->instanceid == $userid) {
 | 
        
           |  |  | 266 |                 // Because we only use user contexts the instance ID is the user ID.
 | 
        
           |  |  | 267 |                 $DB->delete_records('mnet_log', ['userid' => $context->instanceid]);
 | 
        
           |  |  | 268 |             }
 | 
        
           |  |  | 269 |         }
 | 
        
           |  |  | 270 |     }
 | 
        
           | 1 | efrain | 271 | }
 |