Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.
   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   * Data provider.
  19   *
  20   * @package    core_block
  21   * @copyright  2018 Frédéric Massart
  22   * @author     Frédéric Massart <fred@branchup.tech>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  namespace core_block\privacy;
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  use context;
  30  use context_block;
  31  use core_privacy\local\metadata\collection;
  32  use core_privacy\local\request\approved_contextlist;
  33  use core_privacy\local\request\transform;
  34  use core_privacy\local\request\writer;
  35  
  36  /**
  37   * Data provider class.
  38   *
  39   * @package    core_block
  40   * @copyright  2018 Frédéric Massart
  41   * @author     Frédéric Massart <fred@branchup.tech>
  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\subsystem\provider,
  47      \core_privacy\local\request\user_preference_provider,
  48      \core_privacy\local\request\core_userlist_provider {
  49  
  50      /**
  51       * Returns metadata.
  52       *
  53       * @param collection $collection The initialised collection to add items to.
  54       * @return collection A listing of user data stored through this system.
  55       */
  56      public static function get_metadata(collection $collection) : collection {
  57          $collection->add_user_preference('blockIDhidden', 'privacy:metadata:userpref:hiddenblock');
  58          $collection->add_user_preference('docked_block_instance_ID', 'privacy:metadata:userpref:dockedinstance');
  59          return $collection;
  60      }
  61  
  62      /**
  63       * Get the list of contexts that contain user information for the specified user.
  64       *
  65       * @param int $userid The user to search.
  66       * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
  67       */
  68      public static function get_contexts_for_userid(int $userid) : \core_privacy\local\request\contextlist {
  69          global $DB;
  70          $contextlist = new \core_privacy\local\request\contextlist();
  71  
  72          // Fetch the block instance IDs.
  73          $likehidden = $DB->sql_like('name', ':hidden', false, false);
  74          $likedocked = $DB->sql_like('name', ':docked', false, false);
  75          $sql = "userid = :userid AND ($likehidden OR $likedocked)";
  76          $params = [
  77              'userid' => $userid,
  78              'hidden' => 'block%hidden',
  79              'docked' => 'docked_block_instance_%',
  80          ];
  81          $prefs = $DB->get_fieldset_select('user_preferences', 'name', $sql, $params);
  82  
  83          $instanceids = array_unique(array_map(function($prefname) {
  84              if (preg_match('/^block(\d+)hidden$/', $prefname, $matches)) {
  85                  return $matches[1];
  86              } else if (preg_match('/^docked_block_instance_(\d+)$/', $prefname, $matches)) {
  87                  return $matches[1];
  88              }
  89              return 0;
  90          }, $prefs));
  91  
  92          // Find the context of the instances.
  93          if (!empty($instanceids)) {
  94              list($insql, $inparams) = $DB->get_in_or_equal($instanceids, SQL_PARAMS_NAMED);
  95              $sql = "
  96                  SELECT ctx.id
  97                    FROM {context} ctx
  98                   WHERE ctx.instanceid $insql
  99                     AND ctx.contextlevel = :blocklevel";
 100              $params = array_merge($inparams, ['blocklevel' => CONTEXT_BLOCK]);
 101              $contextlist->add_from_sql($sql, $params);
 102          }
 103  
 104          return $contextlist;
 105      }
 106  
 107      /**
 108       * Get the list of users who have data within a context.
 109       *
 110       * @param   \core_privacy\local\request\userlist    $userlist   The userlist containing the list of users who have data in this context/plugin combination.
 111       */
 112      public static function get_users_in_context(\core_privacy\local\request\userlist $userlist) {
 113          global $DB;
 114  
 115          $context = $userlist->get_context();
 116          if ($context->contextlevel != CONTEXT_BLOCK) {
 117              return;
 118          }
 119  
 120          $params = ['docked' => 'docked_block_instance_' . $context->instanceid,
 121                     'hidden' => 'block' . $context->instanceid . 'hidden'];
 122  
 123          $sql = "SELECT userid
 124                    FROM {user_preferences}
 125                   WHERE name = :hidden OR name = :docked";
 126          $userlist->add_from_sql('userid', $sql, $params);
 127      }
 128  
 129      /**
 130       * Export all user data for the specified user, in the specified contexts.
 131       *
 132       * @param approved_contextlist $contextlist The approved contexts to export information for.
 133       */
 134      public static function export_user_data(approved_contextlist $contextlist) {
 135          global $DB;
 136          $userid = $contextlist->get_user()->id;
 137  
 138          // Extract the block instance IDs.
 139          $instanceids = array_reduce($contextlist->get_contexts(), function($carry, $context) {
 140              if ($context->contextlevel == CONTEXT_BLOCK) {
 141                  $carry[] = $context->instanceid;
 142              }
 143              return $carry;
 144          }, []);
 145          if (empty($instanceids)) {
 146              return;
 147          }
 148  
 149          // Query the blocks and their preferences.
 150          list($insql, $inparams) = $DB->get_in_or_equal($instanceids, SQL_PARAMS_NAMED);
 151          $hiddenkey = $DB->sql_concat("'block'", 'bi.id', "'hidden'");
 152          $dockedkey = $DB->sql_concat("'docked_block_instance_'", 'bi.id');
 153          $sql = "
 154              SELECT bi.id, h.value AS prefhidden, d.value AS prefdocked
 155                FROM {block_instances} bi
 156           LEFT JOIN {user_preferences} h
 157                  ON h.userid = :userid1
 158                 AND h.name = $hiddenkey
 159           LEFT JOIN {user_preferences} d
 160                  ON d.userid = :userid2
 161                 AND d.name = $dockedkey
 162               WHERE bi.id $insql
 163                 AND (h.id IS NOT NULL
 164                  OR d.id IS NOT NULL)";
 165          $params = array_merge($inparams, [
 166              'userid1' => $userid,
 167              'userid2' => $userid,
 168          ]);
 169  
 170          // Export all the things.
 171          $dockedstr = get_string('privacy:request:blockisdocked', 'core_block');
 172          $hiddenstr = get_string('privacy:request:blockishidden', 'core_block');
 173          $recordset = $DB->get_recordset_sql($sql, $params);
 174          foreach ($recordset as $record) {
 175              $context = context_block::instance($record->id);
 176              if ($record->prefdocked !== null) {
 177                  writer::with_context($context)->export_user_preference(
 178                      'core_block',
 179                      'block_is_docked',
 180                      transform::yesno($record->prefdocked),
 181                      $dockedstr
 182                  );
 183              }
 184              if ($record->prefhidden !== null) {
 185                  writer::with_context($context)->export_user_preference(
 186                      'core_block',
 187                      'block_is_hidden',
 188                      transform::yesno($record->prefhidden),
 189                      $hiddenstr
 190                  );
 191              }
 192          }
 193          $recordset->close();
 194      }
 195  
 196      /**
 197       * Export all user preferences for the plugin.
 198       *
 199       * @param int $userid The userid of the user whose data is to be exported.
 200       */
 201      public static function export_user_preferences(int $userid) {
 202        // Our preferences aren't site-wide so they are exported in export_user_data.
 203      }
 204  
 205      /**
 206       * Delete all data for all users in the specified context.
 207       *
 208       * @param context $context The specific context to delete data for.
 209       */
 210      public static function delete_data_for_all_users_in_context(context $context) {
 211          global $DB;
 212          if ($context->contextlevel != CONTEXT_BLOCK) {
 213              return;
 214          }
 215  
 216          // Delete the user preferences.
 217          $instanceid = $context->instanceid;
 218          $DB->delete_records_list('user_preferences', 'name', [
 219              "block{$instanceid}hidden",
 220              "docked_block_instance_{$instanceid}"
 221          ]);
 222      }
 223  
 224      /**
 225       * Delete all user data for the specified user, in the specified contexts.
 226       *
 227       * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
 228       */
 229      public static function delete_data_for_user(approved_contextlist $contextlist) {
 230          global $DB;
 231          $userid = $contextlist->get_user()->id;
 232          $prefnames = array_reduce($contextlist->get_contexts(), function($carry, $context) {
 233              if ($context->contextlevel == CONTEXT_BLOCK) {
 234                  $carry[] = "block{$context->instanceid}hidden";
 235                  $carry[] = "docked_block_instance_{$context->instanceid}";
 236              }
 237              return $carry;
 238          }, []);
 239  
 240          if (empty($prefnames)) {
 241              return;
 242          }
 243  
 244          list($insql, $inparams) = $DB->get_in_or_equal($prefnames, SQL_PARAMS_NAMED);
 245          $sql = "userid = :userid AND name $insql";
 246          $params = array_merge($inparams, ['userid' => $userid]);
 247          $DB->delete_records_select('user_preferences', $sql, $params);
 248      }
 249  
 250  
 251      /**
 252       * Delete multiple users within a single context.
 253       *
 254       * @param \core_privacy\local\request\approved_userlist $userlist The approved context and user information to delete
 255       * information for.
 256       */
 257      public static function delete_data_for_users(\core_privacy\local\request\approved_userlist $userlist) {
 258          global $DB;
 259          $context = $userlist->get_context();
 260          if ($context->contextlevel != CONTEXT_BLOCK) {
 261              return;
 262          }
 263  
 264          list($insql, $params) = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED);
 265          $params['hidden'] = 'block' . $context->instanceid . 'hidden';
 266          $params['docked'] = 'docked_block_instance_' . $context->instanceid;
 267  
 268          $DB->delete_records_select('user_preferences', "(name = :hidden OR name = :docked) AND userid $insql", $params);
 269      }
 270  }