MDL-63712 core_message: Data should be in user context, not system
[moodle.git] / message / classes / privacy / provider.php
index b9049e5..5dc24c4 100644 (file)
@@ -175,9 +175,30 @@ class provider implements
      * @return contextlist the list of contexts containing user info for the user.
      */
     public static function get_contexts_for_userid(int $userid) : contextlist {
-        // Messages are in the system context.
+        global $DB;
+
         $contextlist = new contextlist();
-        $contextlist->add_system_context();
+
+        // Messages are in the user context.
+        // For the sake of performance, there is no need to call add_from_sql for each of the below cases.
+        // It is enough to add the user's context as soon as we come to the conclusion that the user has some data.
+        // Also, the order of checking is sorted by the probability of occurrence (just by guess).
+        // There is no need to check the message_user_actions table, as there needs to be a message in order to be a message action.
+        // So, checking messages table would suffice.
+
+        $hasdata = false;
+        $hasdata = $hasdata || $DB->record_exists_select('notifications', 'useridfrom = ? OR useridto = ?', [$userid, $userid]);
+        $hasdata = $hasdata || $DB->record_exists('message_conversation_members', ['userid' => $userid]);
+        $hasdata = $hasdata || $DB->record_exists('messages', ['useridfrom' => $userid]);
+        $hasdata = $hasdata || $DB->record_exists_select('message_contacts', 'userid = ? OR contactid = ?', [$userid, $userid]);
+        $hasdata = $hasdata || $DB->record_exists_select('message_users_blocked', 'userid = ? OR blockeduserid = ?',
+                [$userid, $userid]);
+        $hasdata = $hasdata || $DB->record_exists_select('message_contact_requests', 'userid = ? OR requesteduserid = ?',
+                [$userid, $userid]);
+
+        if ($hasdata) {
+            $contextlist->add_user_context($userid);
+        }
 
         return $contextlist;
     }
@@ -192,17 +213,17 @@ class provider implements
             return;
         }
 
-        // Remove non-system contexts. If it ends up empty then early return.
-        $contexts = array_filter($contextlist->get_contexts(), function($context) {
-            return $context->contextlevel == CONTEXT_SYSTEM;
+        $userid = $contextlist->get_user()->id;
+
+        // Remove non-user and invalid contexts. If it ends up empty then early return.
+        $contexts = array_filter($contextlist->get_contexts(), function($context) use($userid) {
+            return $context->contextlevel == CONTEXT_USER && $context->instanceid == $userid;
         });
 
         if (empty($contexts)) {
             return;
         }
 
-        $userid = $contextlist->get_user()->id;
-
         // Export the contacts.
         self::export_user_data_contacts($userid);
 
@@ -225,19 +246,9 @@ class provider implements
      * @param \context $context the context to delete in.
      */
     public static function delete_data_for_all_users_in_context(\context $context) {
-        global $DB;
-
-        if (!$context instanceof \context_system) {
-            return;
+        if ($context instanceof \context_user) {
+            static::delete_user_data($context->instanceid);
         }
-
-        $DB->delete_records('messages');
-        $DB->delete_records('message_user_actions');
-        $DB->delete_records('message_conversation_members');
-        $DB->delete_records('message_contacts');
-        $DB->delete_records('message_contact_requests');
-        $DB->delete_records('message_users_blocked');
-        $DB->delete_records('notifications');
     }
 
     /**
@@ -246,22 +257,31 @@ class provider implements
      * @param approved_contextlist $contextlist a list of contexts approved for deletion.
      */
     public static function delete_data_for_user(approved_contextlist $contextlist) {
-        global $DB;
-
         if (empty($contextlist->count())) {
             return;
         }
 
-        // Remove non-system contexts. If it ends up empty then early return.
-        $contexts = array_filter($contextlist->get_contexts(), function($context) {
-            return $context->contextlevel == CONTEXT_SYSTEM;
+        $userid = $contextlist->get_user()->id;
+
+        // Remove non-user and invalid contexts. If it ends up empty then early return.
+        $contexts = array_filter($contextlist->get_contexts(), function($context) use($userid) {
+            return $context->contextlevel == CONTEXT_USER && $context->instanceid == $userid;
         });
 
         if (empty($contexts)) {
             return;
         }
 
-        $userid = $contextlist->get_user()->id;
+        static::delete_user_data($userid);
+    }
+
+    /**
+     * Delete all user data for the specified user.
+     *
+     * @param int $userid The user id
+     */
+    protected static function delete_user_data(int $userid) {
+        global $DB;
 
         $DB->delete_records('messages', ['useridfrom' => $userid]);
         $DB->delete_records('message_user_actions', ['userid' => $userid]);
@@ -280,7 +300,7 @@ class provider implements
     protected static function export_user_data_contacts(int $userid) {
         global $DB;
 
-        $context = \context_system::instance();
+        $context = \context_user::instance($userid);
 
         // Get the user's contacts.
         if ($contacts = $DB->get_records_select('message_contacts', 'userid = ? OR contactid = ?', [$userid, $userid], 'id ASC')) {
@@ -302,7 +322,7 @@ class provider implements
     protected static function export_user_data_contact_requests(int $userid) {
         global $DB;
 
-        $context = \context_system::instance();
+        $context = \context_user::instance($userid);
 
         if ($contactrequests = $DB->get_records_select('message_contact_requests', 'userid = ? OR requesteduserid = ?',
                 [$userid, $userid], 'id ASC')) {
@@ -334,7 +354,7 @@ class provider implements
     protected static function export_user_data_blocked_users(int $userid) {
         global $DB;
 
-        $context = \context_system::instance();
+        $context = \context_user::instance($userid);
 
         if ($blockedusers = $DB->get_records('message_users_blocked', ['userid' => $userid], 'id ASC')) {
             $blockedusersdata = [];
@@ -355,7 +375,7 @@ class provider implements
     protected static function export_user_data_messages(int $userid) {
         global $DB;
 
-        $context = \context_system::instance();
+        $context = \context_user::instance($userid);
 
         $sql = "SELECT DISTINCT mcm.conversationid as id
                   FROM {message_conversation_members} mcm
@@ -427,7 +447,7 @@ class provider implements
     protected static function export_user_data_notifications(int $userid) {
         global $DB;
 
-        $context = \context_system::instance();
+        $context = \context_user::instance($userid);
 
         $notificationdata = [];
         $select = "useridfrom = ? OR useridto = ?";