Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.
   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  /**
  18   * Privacy Subsystem implementation for core_repository.
  19   *
  20   * @package    core_repository
  21   * @copyright  2018 Zig Tan <zig@moodle.com>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace core_repository\privacy;
  26  
  27  use core_privacy\local\metadata\collection;
  28  use core_privacy\local\request\approved_contextlist;
  29  use core_privacy\local\request\context;
  30  use core_privacy\local\request\contextlist;
  31  use core_privacy\local\request\transform;
  32  use core_privacy\local\request\writer;
  33  use core_privacy\local\request\userlist;
  34  use \core_privacy\local\request\approved_userlist;
  35  
  36  defined('MOODLE_INTERNAL') || die();
  37  
  38  /**
  39   * Privacy Subsystem for core_repository implementing metadata and plugin providers.
  40   *
  41   * @copyright  2018 Zig Tan <zig@moodle.com>
  42   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  43   */
  44  class provider implements
  45          \core_privacy\local\metadata\provider,
  46          \core_privacy\local\request\core_userlist_provider,
  47          \core_privacy\local\request\plugin\provider {
  48  
  49      /**
  50       * Returns meta data about this system.
  51       *
  52       * @param   collection $collection The initialised collection to add items to.
  53       * @return  collection     A listing of user data stored through this system.
  54       */
  55      public static function get_metadata(collection $collection) : collection {
  56          $collection->add_database_table(
  57              'repository_instances',
  58              [
  59                  'name' => 'privacy:metadata:repository_instances:name',
  60                  'typeid' => 'privacy:metadata:repository_instances:typeid',
  61                  'userid' => 'privacy:metadata:repository_instances:userid',
  62                  'username' => 'privacy:metadata:repository_instances:username',
  63                  'password' => 'privacy:metadata:repository_instances:password',
  64                  'timecreated' => 'privacy:metadata:repository_instances:timecreated',
  65                  'timemodified' => 'privacy:metadata:repository_instances:timemodified',
  66              ],
  67              'privacy:metadata:repository_instances'
  68          );
  69  
  70          $collection->add_plugintype_link('repository', [], 'privacy:metadata:repository');
  71  
  72          return $collection;
  73      }
  74  
  75      /**
  76       * Get the list of contexts that contain user information for the specified user.
  77       *
  78       * @param   int $userid The user to search.
  79       * @return  contextlist   $contextlist  The contextlist containing the list of contexts used in this plugin.
  80       */
  81      public static function get_contexts_for_userid(int $userid) : contextlist {
  82          $contextlist = new contextlist();
  83  
  84          // The repository_instances data is associated at the user context level, so retrieve the user's context id.
  85          $sql = "SELECT c.id
  86                    FROM {repository_instances} ri
  87                    JOIN {context} c ON c.instanceid = ri.userid AND c.contextlevel = :contextuser
  88                   WHERE ri.userid = :userid
  89                GROUP BY c.id";
  90  
  91          $params = [
  92              'contextuser'   => CONTEXT_USER,
  93              'userid'        => $userid
  94          ];
  95  
  96          $contextlist->add_from_sql($sql, $params);
  97          return $contextlist;
  98      }
  99  
 100      /**
 101       * Get the list of users within a specific context.
 102       *
 103       * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
 104       */
 105      public static function get_users_in_context(userlist $userlist) {
 106          $context = $userlist->get_context();
 107  
 108          if (!$context instanceof \context_user) {
 109              return;
 110          }
 111  
 112          $sql = "SELECT userid
 113                    FROM {repository_instances}
 114                   WHERE userid = ?";
 115          $params = [$context->instanceid];
 116  
 117          $userlist->add_from_sql('userid', $sql, $params);
 118      }
 119  
 120      /**
 121       * Export all user data for the specified user, in the specified contexts.
 122       *
 123       * @param   approved_contextlist $contextlist The approved contexts to export information for.
 124       */
 125      public static function export_user_data(approved_contextlist $contextlist) {
 126          global $DB;
 127  
 128          // If the user has repository_instances data, then only the User context should be present so get the first context.
 129          $contexts = $contextlist->get_contexts();
 130          if (count($contexts) == 0) {
 131              return;
 132          }
 133          $context = reset($contexts);
 134  
 135          // Sanity check that context is at the User context level, then get the userid.
 136          if ($context->contextlevel !== CONTEXT_USER) {
 137              return;
 138          }
 139          $userid = $context->instanceid;
 140  
 141          $sql = "SELECT DISTINCT
 142                         ri.id as id,
 143                         r.type as type,
 144                         ri.name as name,
 145                         ri.timecreated as timecreated,
 146                         ri.timemodified as timemodified
 147                    FROM {repository_instances} ri
 148                    JOIN {repository} r ON r.id = ri.typeid
 149                   WHERE ri.userid = :userid";
 150  
 151          $params = [
 152              'userid' => $userid
 153          ];
 154  
 155          $repositoryinstances = $DB->get_records_sql($sql, $params);
 156  
 157          foreach ($repositoryinstances as $repositoryinstance) {
 158              // The repository_instances data export is organised in: {User Context}/Repository plug-ins/{Plugin Name}/data.json.
 159              $subcontext = [
 160                  get_string('plugin', 'core_repository'),
 161                  get_string('pluginname', 'repository_' . $repositoryinstance->type)
 162              ];
 163  
 164              $data = (object) [
 165                  'type' => $repositoryinstance->type,
 166                  'name' => $repositoryinstance->name,
 167                  'timecreated' => transform::datetime($repositoryinstance->timecreated),
 168                  'timemodified' => transform::datetime($repositoryinstance->timemodified)
 169              ];
 170  
 171              writer::with_context($context)->export_data($subcontext, $data);
 172          }
 173      }
 174  
 175      /**
 176       * Delete all data for all users in the specified context.
 177       *
 178       * @param   context $context The specific context to delete data for.
 179       */
 180      public static function delete_data_for_all_users_in_context(\context $context) {
 181          global $DB;
 182  
 183          // Sanity check that context is at the User context level, then get the userid.
 184          if ($context->contextlevel !== CONTEXT_USER) {
 185              return;
 186          }
 187          $userid = $context->instanceid;
 188  
 189          // Delete the repository_instances records created for the userid.
 190          $DB->delete_records('repository_instances', ['userid' => $userid]);
 191      }
 192  
 193      /**
 194       * Delete multiple users within a single context.
 195       *
 196       * @param approved_userlist $userlist The approved context and user information to delete information for.
 197       */
 198      public static function delete_data_for_users(approved_userlist $userlist) {
 199          global $DB;
 200  
 201          $context = $userlist->get_context();
 202  
 203          if ($context instanceof \context_user) {
 204              $DB->delete_records('repository_instances', ['userid' => $context->instanceid]);
 205          }
 206      }
 207  
 208      /**
 209       * Delete all user data for the specified user, in the specified contexts.
 210       *
 211       * @param   approved_contextlist $contextlist The approved contexts and user information to delete information for.
 212       */
 213      public static function delete_data_for_user(approved_contextlist $contextlist) {
 214          global $DB;
 215  
 216          // If the user has repository_instances data, then only the User context should be present so get the first context.
 217          $contexts = $contextlist->get_contexts();
 218          if (count($contexts) == 0) {
 219              return;
 220          }
 221          $context = reset($contexts);
 222  
 223          // Sanity check that context is at the User context level, then get the userid.
 224          if ($context->contextlevel !== CONTEXT_USER) {
 225              return;
 226          }
 227          $userid = $context->instanceid;
 228  
 229          // Delete the repository_instances records created for the userid.
 230          $DB->delete_records('repository_instances', ['userid' => $userid]);
 231      }
 232  
 233  }