Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are 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   * Privacy provider implementation for core_contentbank.
  19   *
  20   * @package    core_contentbank
  21   * @copyright  2020 Amaia Anabitarte <amaia@moodle.com>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace core_contentbank\privacy;
  26  
  27  use core_privacy\local\metadata\collection;
  28  use core_privacy\local\request\approved_contextlist;
  29  use core_privacy\local\request\contextlist;
  30  use core_privacy\local\request\transform;
  31  use core_privacy\local\request\writer;
  32  use core_privacy\local\request\userlist;
  33  use core_privacy\local\request\approved_userlist;
  34  use context_system;
  35  use context_coursecat;
  36  use context_course;
  37  
  38  /**
  39   * Privacy provider implementation for core_contentbank.
  40   *
  41   * @copyright  2020 Amaia Anabitarte <amaia@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      \core_privacy\local\request\user_preference_provider {
  49  
  50      /**
  51       * Returns meta data about this system.
  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_database_table('contentbank_content', [
  58              'name' => 'privacy:metadata:content:name',
  59              'contenttype' => 'privacy:metadata:content:contenttype',
  60              'usercreated' => 'privacy:metadata:content:usercreated',
  61              'usermodified' => 'privacy:metadata:content:usermodified',
  62              'timecreated' => 'privacy:metadata:content:timecreated',
  63              'timemodified' => 'privacy:metadata:content:timemodified',
  64          ], 'privacy:metadata:contentbankcontent');
  65  
  66          return $collection;
  67      }
  68  
  69      /**
  70       * Export all user preferences for the contentbank
  71       *
  72       * @param int $userid The userid of the user whose data is to be exported.
  73       */
  74      public static function export_user_preferences(int $userid) {
  75          $preference = get_user_preferences('core_contentbank_view_list', null, $userid);
  76          if (isset($preference)) {
  77              writer::export_user_preference(
  78                      'core_contentbank',
  79                      'core_contentbank_view_list',
  80                      $preference,
  81                      get_string('privacy:request:preference:set', 'core_contentbank', (object) [
  82                              'name' => 'core_contentbank_view_list',
  83                              'value' => $preference,
  84                      ])
  85              );
  86          }
  87      }
  88  
  89      /**
  90       * Get the list of contexts that contain user information for the specified user.
  91       *
  92       * @param   int $userid The user to search.
  93       * @return  contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
  94       */
  95      public static function get_contexts_for_userid(int $userid): contextlist {
  96          $sql = "SELECT DISTINCT ctx.id
  97                    FROM {context} ctx
  98                    JOIN {contentbank_content} cb
  99                         ON cb.contextid = ctx.id
 100                   WHERE cb.usercreated = :userid
 101                         AND (ctx.contextlevel = :contextlevel1
 102                             OR ctx.contextlevel = :contextlevel2
 103                             OR ctx.contextlevel = :contextlevel3)";
 104  
 105          $params = [
 106              'userid'        => $userid,
 107              'contextlevel1' => CONTEXT_SYSTEM,
 108              'contextlevel2' => CONTEXT_COURSECAT,
 109              'contextlevel3' => CONTEXT_COURSE,
 110          ];
 111  
 112          $contextlist = new contextlist();
 113          $contextlist->add_from_sql($sql, $params);
 114  
 115          return $contextlist;
 116      }
 117  
 118      /**
 119       * Get the list of users within a specific context.
 120       *
 121       * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
 122       */
 123      public static function get_users_in_context(userlist $userlist) {
 124          $context = $userlist->get_context();
 125  
 126          $allowedcontextlevels = [
 127              CONTEXT_SYSTEM,
 128              CONTEXT_COURSECAT,
 129              CONTEXT_COURSE,
 130          ];
 131  
 132          if (!in_array($context->contextlevel, $allowedcontextlevels)) {
 133              return;
 134          }
 135  
 136          $sql = "SELECT cb.usercreated as userid
 137                    FROM {contentbank_content} cb
 138                   WHERE cb.contextid = :contextid";
 139  
 140          $params = [
 141              'contextid' => $context->id
 142          ];
 143  
 144          $userlist->add_from_sql('userid', $sql, $params);
 145      }
 146  
 147      /**
 148       * Export all user data for the specified user, in the specified contexts.
 149       *
 150       * @param approved_contextlist $contextlist The approved contexts to export information for.
 151       */
 152      public static function export_user_data(approved_contextlist $contextlist) {
 153          global $DB;
 154  
 155          // Remove contexts different from SYSTEM, COURSECAT or COURSE.
 156          $contextids = array_reduce($contextlist->get_contexts(), function($carry, $context) {
 157              if ($context->contextlevel == CONTEXT_SYSTEM || $context->contextlevel == CONTEXT_COURSECAT
 158                  || $context->contextlevel == CONTEXT_COURSE) {
 159                  $carry[] = $context->id;
 160              }
 161              return $carry;
 162          }, []);
 163  
 164          if (empty($contextids)) {
 165              return;
 166          }
 167  
 168          $userid = $contextlist->get_user()->id;
 169  
 170          list($contextsql, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED);
 171          // Retrieve the contentbank_content records created for the user.
 172          $sql = "SELECT cb.id,
 173                         cb.name,
 174                         cb.contenttype,
 175                         cb.usercreated,
 176                         cb.usermodified,
 177                         cb.timecreated,
 178                         cb.timemodified,
 179                         cb.contextid
 180                    FROM {contentbank_content} cb
 181                   WHERE cb.usercreated = :userid
 182                         AND cb.contextid {$contextsql}
 183                   ORDER BY cb.contextid";
 184  
 185          $params = ['userid' => $userid] + $contextparams;
 186  
 187          $contents = $DB->get_recordset_sql($sql, $params);
 188          $data = [];
 189          $lastcontextid = null;
 190          $subcontext = [
 191              get_string('name', 'core_contentbank'),
 192          ];
 193          foreach ($contents as $content) {
 194              // The core_contentbank data export is organised in:
 195              // {Sytem|Course Category|Course Context Level}/Content/data.json.
 196              if ($lastcontextid && $lastcontextid != $content->contextid) {
 197                  $context = \context::instance_by_id($lastcontextid);
 198                  writer::with_context($context)->export_data($subcontext, (object)$data);
 199                  $data = [];
 200              }
 201              $data[] = (object) [
 202                  'name' => $content->name,
 203                  'contenttype' => $content->contenttype,
 204                  'usercreated' => transform::user($content->usercreated),
 205                  'usermodified' => transform::user($content->usermodified),
 206                  'timecreated' => transform::datetime($content->timecreated),
 207                  'timemodified' => transform::datetime($content->timemodified)
 208              ];
 209              $lastcontextid = $content->contextid;
 210  
 211              // The core_contentbank files export is organised in:
 212              // {Sytem|Course Category|Course Context Level}/Content/_files/public/_itemid/filename.
 213              $context = \context::instance_by_id($lastcontextid);
 214              writer::with_context($context)->export_area_files($subcontext, 'contentbank', 'public', $content->id);
 215          }
 216          if (!empty($data)) {
 217              $context = \context::instance_by_id($lastcontextid);
 218              writer::with_context($context)->export_data($subcontext, (object)$data);
 219          }
 220          $contents->close();
 221      }
 222  
 223      /**
 224       * Delete all data for all users in the specified context.
 225       *
 226       * @param   context $context The specific context to delete data for.
 227       */
 228      public static function delete_data_for_all_users_in_context(\context $context) {
 229          global $DB;
 230  
 231          if (!$context instanceof context_system && !$context instanceof context_coursecat
 232                  && !$context instanceof context_course) {
 233              return;
 234          }
 235  
 236          static::delete_data($context, []);
 237      }
 238  
 239      /**
 240       * Delete multiple users within a single context.
 241       *
 242       * @param approved_userlist $userlist The approved context and user information to delete information for.
 243       */
 244      public static function delete_data_for_users(approved_userlist $userlist) {
 245          $context = $userlist->get_context();
 246  
 247          if (!$context instanceof context_system && !$context instanceof context_coursecat
 248                  && !$context instanceof context_course) {
 249              return;
 250          }
 251  
 252          static::delete_data($context, $userlist->get_userids());
 253      }
 254  
 255      /**
 256       * Delete all user data for the specified user, in the specified contexts.
 257       *
 258       * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
 259       */
 260      public static function delete_data_for_user(approved_contextlist $contextlist) {
 261          if (empty($contextlist->count())) {
 262              return;
 263          }
 264  
 265          $userid = $contextlist->get_user()->id;
 266          foreach ($contextlist->get_contexts() as $context) {
 267              if (!$context instanceof context_system && !$context instanceof context_coursecat
 268              && !$context instanceof context_course) {
 269                  continue;
 270              }
 271              static::delete_data($context, [$userid]);
 272          }
 273      }
 274  
 275      /**
 276       * Delete data related to a context and users (if defined).
 277       *
 278       * @param context $context A context.
 279       * @param array $userids The user IDs.
 280       */
 281      protected static function delete_data(\context $context, array $userids) {
 282          global $DB;
 283  
 284          $params = ['contextid' => $context->id];
 285          $select = 'contextid = :contextid';
 286  
 287          // Delete the Content Bank files.
 288          if (!empty($userids)) {
 289              list($insql, $inparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
 290              $params += $inparams;
 291              $select .= ' AND usercreated '.$insql;
 292          }
 293          $fs = get_file_storage();
 294          $contents = $DB->get_records_select('contentbank_content',
 295              $select, $params);
 296          foreach ($contents as $content) {
 297              $fs->delete_area_files($content->contextid, 'contentbank', 'public', $content->id);
 298          }
 299  
 300          // Delete all the contents.
 301          $DB->delete_records_select('contentbank_content', $select, $params);
 302      }
 303  }