correct logic for tracking the highest seen post number so its always consistent

This commit is contained in:
Sam 2013-04-08 11:12:52 +10:00
parent fd31f946ee
commit 11ff0ccd03
6 changed files with 21 additions and 18 deletions

View file

@ -28,12 +28,6 @@ Discourse.ScreenTrack = Ember.Object.extend({
};
},
guessedSeen: function(postNumber) {
if (postNumber > (this.highestSeen || 0)) {
this.highestSeen = postNumber;
}
},
// Reset our timers
reset: function() {
this.lastTick = new Date().getTime();
@ -93,16 +87,21 @@ Discourse.ScreenTrack = Ember.Object.extend({
timing.time = 0;
});
topicId = this.get('topic_id');
var highestSeen = 0;
$.each(newTimings, function(postNumber){
highestSeen = Math.max(highestSeen, parseInt(postNumber, 10));
});
highestSeenByTopic = Discourse.get('highestSeenByTopic');
if ((highestSeenByTopic[topicId] || 0) < this.highestSeen) {
highestSeenByTopic[topicId] = this.highestSeen;
if ((highestSeenByTopic[topicId] || 0) < highestSeen) {
highestSeenByTopic[topicId] = highestSeen;
}
if (!Object.isEmpty(newTimings)) {
Discourse.ajax(Discourse.getURL('/topics/timings'), {
data: {
timings: newTimings,
topic_time: this.topicTime,
highest_seen: this.highestSeen,
topic_id: topicId
},
cache: false,

View file

@ -181,8 +181,6 @@ Discourse.TopicView = Discourse.View.extend(Discourse.Scrolling, {
}
if (!post.get('read')) {
post.set('read', true);
screenTrack = this.get('screenTrack');
if (screenTrack) { screenTrack.guessedSeen(postNumber); }
}
return post.get('post_number');
}

View file

@ -151,7 +151,6 @@ class TopicsController < ApplicationController
PostTiming.process_timings(
current_user,
params[:topic_id].to_i,
params[:highest_seen].to_i,
params[:topic_time].to_i,
(params[:timings] || []).map{|post_number, t| [post_number.to_i, t.to_i]}
)

View file

@ -37,15 +37,19 @@ class PostTiming < ActiveRecord::Base
end
def self.process_timings(current_user, topic_id, highest_seen, topic_time, timings)
def self.process_timings(current_user, topic_id, topic_time, timings)
current_user.update_time_read!
highest_seen = 1
timings.each do |post_number, time|
if post_number >= 0
PostTiming.record_timing(topic_id: topic_id,
post_number: post_number,
user_id: current_user.id,
msecs: time)
highest_seen = post_number.to_i > highest_seen ?
post_number.to_i : highest_seen
end
end

View file

@ -117,6 +117,10 @@ class TopicUser < ActiveRecord::Base
threshold: SiteSetting.auto_track_topics_after
}
# In case anyone seens "seen_post_count" and gets confused, like I do.
# seen_post_count represents the highest_post_number of the topic when
# the user visited it. It may be out of alignement with last_read, meaning
# ... user visited the topic but did not read the posts
rows = exec_sql("UPDATE topic_users
SET
last_read_post_number = greatest(:post_number, tu.last_read_post_number),
@ -176,17 +180,16 @@ class TopicUser < ActiveRecord::Base
UPDATE topic_users t
SET
last_read_post_number = last_read,
seen_post_count = post_count
seen_post_count = GREATEST(t.seen_post_count, last_read)
FROM (
SELECT topic_id, user_id, COUNT(*) post_count, MAX(post_number) last_read
SELECT topic_id, user_id, MAX(post_number) last_read
FROM post_timings
GROUP BY topic_id, user_id
) as X
WHERE X.topic_id = t.topic_id AND
X.user_id = t.user_id AND
(
last_read_post_number <> last_read OR
seen_post_count <> post_count
last_read_post_number <> last_read
)
SQL
end

View file

@ -21,7 +21,7 @@ describe PostTiming do
post.user.unread_notifications_by_type.should == { Notification.types[:liked] => 1 }
PostTiming.process_timings(post.user, post.topic_id, 1, 100, [[post.post_number, 100]])
PostTiming.process_timings(post.user, post.topic_id, 1, [[post.post_number, 100]])
post.user.reload
post.user.unread_notifications_by_type.should == {}