From 611a5ef714a3b46dccbc42281e43f015bbaccc2a Mon Sep 17 00:00:00 2001 From: Andrew Nicols <andrew@nicols.co.uk> Date: Wed, 29 Oct 2014 09:28:55 +0800 Subject: [PATCH] MDL-25057 mod_forum: Stop duplicating forum_read posts from cron This also includes an upgrade script to delete the existing duplicates. --- mod/forum/db/upgrade.php | 24 +++++++++++ mod/forum/lib.php | 89 ++++++++++++++++++++-------------------- mod/forum/version.php | 2 +- 3 files changed, 70 insertions(+), 45 deletions(-) diff --git a/mod/forum/db/upgrade.php b/mod/forum/db/upgrade.php index c241541f201..06a93774052 100644 --- a/mod/forum/db/upgrade.php +++ b/mod/forum/db/upgrade.php @@ -200,5 +200,29 @@ function xmldb_forum_upgrade($oldversion) { upgrade_mod_savepoint(true, 2014081900, 'forum'); } + if ($oldversion < 2014103000) { + // Find records with multiple userid/postid combinations and find the lowest ID. + // Later we will remove all those which don't match this ID. + $sql = " + SELECT MIN(id) as lowid, userid, postid + FROM {forum_read} + GROUP BY userid, postid + HAVING COUNT(id) > 1"; + + if ($duplicatedrows = $DB->get_recordset_sql($sql)) { + foreach ($duplicatedrows as $row) { + $DB->delete_records_select('forum_read', 'userid = ? AND postid = ? AND id <> ?', array( + $row->userid, + $row->postid, + $row->lowid, + )); + } + } + $duplicatedrows->close(); + + // Forum savepoint reached. + upgrade_mod_savepoint(true, 2014103000, 'forum'); + } + return true; } diff --git a/mod/forum/lib.php b/mod/forum/lib.php index 1ecd6c33623..54fcac2dd71 100644 --- a/mod/forum/lib.php +++ b/mod/forum/lib.php @@ -5962,57 +5962,58 @@ function forum_tp_mark_posts_read($user, $postids) { return $status; } - list($usql, $params) = $DB->get_in_or_equal($postids); - $params[] = $user->id; + list($usql, $postidparams) = $DB->get_in_or_equal($postids, SQL_PARAMS_NAMED, 'postid'); - $sql = "SELECT id - FROM {forum_read} - WHERE postid $usql AND userid = ?"; - if ($existing = $DB->get_records_sql($sql, $params)) { - $existing = array_keys($existing); + $insertparams = array( + 'userid1' => $user->id, + 'userid2' => $user->id, + 'userid3' => $user->id, + 'firstread' => $now, + 'lastread' => $now, + 'cutoffdate' => $cutoffdate, + ); + $params = array_merge($postidparams, $insertparams); + + if ($CFG->forum_allowforcedreadtracking) { + $trackingsql = "AND (f.trackingtype = ".FORUM_TRACKING_FORCED." + OR (f.trackingtype = ".FORUM_TRACKING_OPTIONAL." AND tf.id IS NULL))"; } else { - $existing = array(); + $trackingsql = "AND ((f.trackingtype = ".FORUM_TRACKING_OPTIONAL." OR f.trackingtype = ".FORUM_TRACKING_FORCED.") + AND tf.id IS NULL)"; } - $new = array_diff($postids, $existing); + // First insert any new entries. + $sql = "INSERT INTO {forum_read} (userid, postid, discussionid, forumid, firstread, lastread) - if ($new) { - list($usql, $new_params) = $DB->get_in_or_equal($new); - $params = array($user->id, $now, $now, $user->id); - $params = array_merge($params, $new_params); - $params[] = $cutoffdate; + SELECT :userid1, p.id, p.discussion, d.forum, :firstread, :lastread + FROM {forum_posts} p + JOIN {forum_discussions} d ON d.id = p.discussion + JOIN {forum} f ON f.id = d.forum + LEFT JOIN {forum_track_prefs} tf ON (tf.userid = :userid2 AND tf.forumid = f.id) + LEFT JOIN {forum_read} fr ON ( + fr.userid = :userid3 + AND fr.postid = p.id + AND fr.discussionid = d.id + AND fr.forumid = f.id + ) + WHERE p.id $usql + AND p.modified >= :cutoffdate + $trackingsql + AND fr.id IS NULL"; - if ($CFG->forum_allowforcedreadtracking) { - $trackingsql = "AND (f.trackingtype = ".FORUM_TRACKING_FORCED." - OR (f.trackingtype = ".FORUM_TRACKING_OPTIONAL." AND tf.id IS NULL))"; - } else { - $trackingsql = "AND ((f.trackingtype = ".FORUM_TRACKING_OPTIONAL." OR f.trackingtype = ".FORUM_TRACKING_FORCED.") - AND tf.id IS NULL)"; - } + $status = $DB->execute($sql, $params) && $status; - $sql = "INSERT INTO {forum_read} (userid, postid, discussionid, forumid, firstread, lastread) - - SELECT ?, p.id, p.discussion, d.forum, ?, ? - FROM {forum_posts} p - JOIN {forum_discussions} d ON d.id = p.discussion - JOIN {forum} f ON f.id = d.forum - LEFT JOIN {forum_track_prefs} tf ON (tf.userid = ? AND tf.forumid = f.id) - WHERE p.id $usql - AND p.modified >= ? - $trackingsql"; - $status = $DB->execute($sql, $params) && $status; - } - - if ($existing) { - list($usql, $new_params) = $DB->get_in_or_equal($existing); - $params = array($now, $user->id); - $params = array_merge($params, $new_params); - - $sql = "UPDATE {forum_read} - SET lastread = ? - WHERE userid = ? AND postid $usql"; - $status = $DB->execute($sql, $params) && $status; - } + // Then update all records. + $updateparams = array( + 'userid' => $user->id, + 'lastread' => $now, + ); + $params = array_merge($postidparams, $updateparams); + $status = $DB->set_field_select('forum_read', 'lastread', $now, ' + userid = :userid + AND lastread <> :lastread + AND postid ' . $usql, + $params) && $status; return $status; } diff --git a/mod/forum/version.php b/mod/forum/version.php index fc107f3ff91..5cbe4824a5b 100644 --- a/mod/forum/version.php +++ b/mod/forum/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2014082101; // The current module version (Date: YYYYMMDDXX) +$plugin->version = 2014103000; // The current module version (Date: YYYYMMDDXX) $plugin->requires = 2014050800; // Requires this Moodle version $plugin->component = 'mod_forum'; // Full name of the plugin (used for diagnostics)