Search moodle.org's
Developer Documentation

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.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   * 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  }