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.

Differences Between: [Versions 39 and 402] [Versions 39 and 403]

   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 quizaccess_seb.
  19   *
  20   * @package    quizaccess_seb
  21   * @author     Andrew Madden <andrewmadden@catalyst-au.net>
  22   * @copyright  2019 Catalyst IT
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  namespace quizaccess_seb\privacy;
  27  
  28  use context;
  29  use core_privacy\local\metadata\collection;
  30  use core_privacy\local\request\approved_contextlist;
  31  use core_privacy\local\request\approved_userlist;
  32  use core_privacy\local\request\contextlist;
  33  use core_privacy\local\request\transform;
  34  use core_privacy\local\request\userlist;
  35  use core_privacy\local\request\writer;
  36  use quizaccess_seb\quiz_settings;
  37  use quizaccess_seb\template;
  38  
  39  defined('MOODLE_INTERNAL') || die();
  40  
  41  /**
  42   * Privacy Subsystem implementation for quizaccess_seb.
  43   *
  44   * @copyright  2020 Catalyst IT
  45   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  46   */
  47  class provider implements
  48      \core_privacy\local\metadata\provider,
  49      \core_privacy\local\request\core_userlist_provider,
  50      \core_privacy\local\request\plugin\provider {
  51  
  52      /**
  53       * Retrieve the user metadata stored by plugin.
  54       *
  55       * @param collection $collection Collection of metadata.
  56       * @return collection Collection of metadata.
  57       */
  58      public static function get_metadata(collection $collection): collection {
  59          $collection->add_database_table(
  60              'quizaccess_seb_quizsettings',
  61               [
  62                   'quizid' => 'privacy:metadata:quizaccess_seb_quizsettings:quizid',
  63                   'usermodified' => 'privacy:metadata:quizaccess_seb_quizsettings:usermodified',
  64                   'timecreated' => 'privacy:metadata:quizaccess_seb_quizsettings:timecreated',
  65                   'timemodified' => 'privacy:metadata:quizaccess_seb_quizsettings:timemodified',
  66               ],
  67              'privacy:metadata:quizaccess_seb_quizsettings'
  68          );
  69  
  70          $collection->add_database_table(
  71              'quizaccess_seb_template',
  72              [
  73                  'usermodified' => 'privacy:metadata:quizaccess_seb_template:usermodified',
  74                  'timecreated' => 'privacy:metadata:quizaccess_seb_template:timecreated',
  75                  'timemodified' => 'privacy:metadata:quizaccess_seb_template:timemodified',
  76              ],
  77              'privacy:metadata:quizaccess_seb_template'
  78          );
  79  
  80          return $collection;
  81      }
  82  
  83      /**
  84       * Get the list of contexts that contain user information for the specified user.
  85       *
  86       * @param int $userid The user to search.
  87       * @return contextlist A list of contexts used in this plugin.
  88       */
  89      public static function get_contexts_for_userid(int $userid): contextlist {
  90          $contextlist = new contextlist();
  91  
  92          // The data is associated at the module context level, so retrieve the quiz context id.
  93          $sql = "SELECT c.id
  94                    FROM {quizaccess_seb_quizsettings} qs
  95                    JOIN {course_modules} cm ON cm.instance = qs.quizid
  96                    JOIN {modules} m ON cm.module = m.id AND m.name = :modulename
  97                    JOIN {context} c ON c.instanceid = cm.id AND c.contextlevel = :context
  98                   WHERE qs.usermodified = :userid
  99                GROUP BY c.id";
 100  
 101          $params = [
 102              'context' => CONTEXT_MODULE,
 103              'modulename' => 'quiz',
 104              'userid' => $userid
 105          ];
 106  
 107          $contextlist->add_from_sql($sql, $params);
 108  
 109          $sql = "SELECT c.id
 110                    FROM {quizaccess_seb_template} tem
 111                    JOIN {quizaccess_seb_quizsettings} qs ON qs.templateid = tem.id
 112                    JOIN {course_modules} cm ON cm.instance = qs.quizid
 113                    JOIN {modules} m ON cm.module = m.id AND m.name = :modulename
 114                    JOIN {context} c ON c.instanceid = cm.id AND c.contextlevel = :context
 115                   WHERE qs.usermodified = :userid
 116                GROUP BY c.id";
 117  
 118          $contextlist->add_from_sql($sql, $params);
 119  
 120          return $contextlist;
 121      }
 122  
 123      /**
 124       * Export all user data for the specified user, in the specified contexts.
 125       *
 126       * @param approved_contextlist $contextlist The approved contexts to export information for.
 127       */
 128      public static function export_user_data(approved_contextlist $contextlist) {
 129          global $DB;
 130  
 131          // Get all cmids that correspond to the contexts for a user.
 132          $cmids = [];
 133          foreach ($contextlist->get_contexts() as $context) {
 134              if ($context->contextlevel === CONTEXT_MODULE) {
 135                  $cmids[] = $context->instanceid;
 136              }
 137          }
 138  
 139          // Do nothing if no matching quiz settings are found for the user.
 140          if (empty($cmids)) {
 141              return;
 142          }
 143  
 144          list($insql, $params) = $DB->get_in_or_equal($cmids, SQL_PARAMS_NAMED);
 145          $params['modulename'] = 'quiz';
 146  
 147          // SEB quiz settings.
 148          $sql = "SELECT qs.id as id,
 149                         qs.quizid as quizid,
 150                         qs.usermodified as usermodified,
 151                         qs.timecreated as timecreated,
 152                         qs.timemodified as timemodified
 153                    FROM {quizaccess_seb_quizsettings} qs
 154                    JOIN {course_modules} cm ON cm.instance = qs.quizid
 155                    JOIN {modules} m ON cm.module = m.id AND m.name = :modulename
 156                   WHERE cm.id {$insql}";
 157  
 158          $quizsettingslist = $DB->get_records_sql($sql, $params);
 159          $index = 0;
 160          foreach ($quizsettingslist as $quizsettings) {
 161              // Data export is organised in: {Context}/{Plugin Name}/{Table name}/{index}/data.json.
 162              $index++;
 163              $subcontext = [
 164                  get_string('pluginname', 'quizaccess_seb'),
 165                  quiz_settings::TABLE,
 166                  $index
 167              ];
 168  
 169              $data = (object) [
 170                  'quizid' => $quizsettings->quizid,
 171                  'usermodified' => $quizsettings->usermodified,
 172                  'timecreated' => transform::datetime($quizsettings->timecreated),
 173                  'timemodified' => transform::datetime($quizsettings->timemodified)
 174              ];
 175  
 176              writer::with_context($context)->export_data($subcontext, $data);
 177          }
 178  
 179          // SEB template settings.
 180          $sql = "SELECT tem.id as id,
 181                         qs.quizid as quizid,
 182                         tem.usermodified as usermodified,
 183                         tem.timecreated as timecreated,
 184                         tem.timemodified as timemodified
 185                    FROM {quizaccess_seb_template} tem
 186                    JOIN {quizaccess_seb_quizsettings} qs ON qs.templateid = tem.id
 187                    JOIN {course_modules} cm ON cm.instance = qs.quizid
 188                    JOIN {modules} m ON cm.module = m.id AND m.name = :modulename
 189                   WHERE cm.id {$insql}";
 190  
 191          $templatesettingslist = $DB->get_records_sql($sql, $params);
 192          $index = 0;
 193          foreach ($templatesettingslist as $templatesetting) {
 194              // Data export is organised in: {Context}/{Plugin Name}/{Table name}/{index}/data.json.
 195              $index++;
 196              $subcontext = [
 197                  get_string('pluginname', 'quizaccess_seb'),
 198                  template::TABLE,
 199                  $index
 200              ];
 201  
 202              $data = (object) [
 203                  'templateid' => $templatesetting->id,
 204                  'quizid' => $templatesetting->quizid,
 205                  'usermodified' => $templatesetting->usermodified,
 206                  'timecreated' => transform::datetime($templatesetting->timecreated),
 207                  'timemodified' => transform::datetime($templatesetting->timemodified)
 208              ];
 209  
 210              writer::with_context($context)->export_data($subcontext, $data);
 211          }
 212      }
 213  
 214      /**
 215       * Delete all data for all users in the specified context.
 216       *
 217       * @param context $context The specific context to delete data for.
 218       */
 219      public static function delete_data_for_all_users_in_context(\context $context) {
 220          global $DB;
 221  
 222          // Sanity check that context is at the module context level, then get the quizid.
 223          if ($context->contextlevel !== CONTEXT_MODULE) {
 224              return;
 225          }
 226  
 227          $cmid = $context->instanceid;
 228          $quizid = $DB->get_field('course_modules', 'instance', ['id' => $cmid]);
 229  
 230          $params['quizid'] = $quizid;
 231          $select = "id IN (SELECT templateid FROM {quizaccess_seb_quizsettings} qs WHERE qs.quizid = :quizid)";
 232          $DB->set_field_select('quizaccess_seb_quizsettings', 'usermodified', 0, "quizid = :quizid", $params);
 233          $DB->set_field_select('quizaccess_seb_template', 'usermodified', 0, $select, $params);
 234      }
 235  
 236      /**
 237       * Delete all user data for the specified user, in the specified contexts.
 238       *
 239       * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
 240       */
 241      public static function delete_data_for_user(approved_contextlist $contextlist) {
 242          global $DB;
 243  
 244          // If the user has data, then only the User context should be present so get the first context.
 245          $contexts = $contextlist->get_contexts();
 246          if (count($contexts) == 0) {
 247              return;
 248          }
 249  
 250          $params['usermodified'] = $contextlist->get_user()->id;
 251          $DB->set_field_select('quizaccess_seb_quizsettings', 'usermodified', 0, "usermodified = :usermodified", $params);
 252          $DB->set_field_select('quizaccess_seb_template', 'usermodified', 0, "usermodified = :usermodified", $params);
 253      }
 254  
 255      /**
 256       * Get the list of users who have data within a context.
 257       *
 258       * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
 259       */
 260      public static function get_users_in_context(userlist $userlist) {
 261          $context = $userlist->get_context();
 262  
 263          if (!$context instanceof \context_module) {
 264              return;
 265          }
 266  
 267          // The data is associated at the quiz module context level, so retrieve the user's context id.
 268          $sql = "SELECT qs.usermodified AS userid
 269                    FROM {quizaccess_seb_quizsettings} qs
 270                    JOIN {course_modules} cm ON cm.instance = qs.quizid
 271                    JOIN {modules} m ON cm.module = m.id AND m.name = ?
 272                   WHERE cm.id = ?";
 273          $params = ['quiz', $context->instanceid];
 274          $userlist->add_from_sql('userid', $sql, $params);
 275      }
 276  
 277      /**
 278       * Delete multiple users within a single context.
 279       *
 280       * @param approved_userlist $userlist The approved context and user information to delete information for.
 281       */
 282      public static function delete_data_for_users(approved_userlist $userlist) {
 283          global $DB;
 284          $context = $userlist->get_context();
 285  
 286          // Sanity check that context is at the Module context level.
 287          if ($context->contextlevel !== CONTEXT_MODULE) {
 288              return;
 289          }
 290  
 291          $userids = $userlist->get_userids();
 292          list($insql, $inparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
 293  
 294          $DB->set_field_select('quizaccess_seb_quizsettings', 'usermodified', 0, "usermodified {$insql}", $inparams);
 295          $DB->set_field_select('quizaccess_seb_template', 'usermodified', 0, "usermodified {$insql}", $inparams);
 296      }
 297  }