mirror of
https://github.com/viq/NewsBlur.git
synced 2025-09-18 21:43:31 +00:00
Backend for marking feeds/folders as read at a specific timestamp.
This commit is contained in:
parent
b250369312
commit
d8ed12f15b
7 changed files with 88 additions and 63 deletions
|
@ -404,31 +404,37 @@ class UserSubscription(models.Model):
|
||||||
r.srem(read_stories_key, *stale_story_hashes)
|
r.srem(read_stories_key, *stale_story_hashes)
|
||||||
r.srem("RS:%s" % self.feed_id, *stale_story_hashes)
|
r.srem("RS:%s" % self.feed_id, *stale_story_hashes)
|
||||||
|
|
||||||
def mark_feed_read(self):
|
def mark_feed_read(self, cutoff_date=None):
|
||||||
if (self.unread_count_negative == 0
|
if (self.unread_count_negative == 0
|
||||||
and self.unread_count_neutral == 0
|
and self.unread_count_neutral == 0
|
||||||
and self.unread_count_positive == 0
|
and self.unread_count_positive == 0
|
||||||
and not self.needs_unread_recalc):
|
and not self.needs_unread_recalc):
|
||||||
return
|
return
|
||||||
|
|
||||||
now = datetime.datetime.utcnow()
|
recount = True
|
||||||
|
|
||||||
# Use the latest story to get last read time.
|
# Use the latest story to get last read time.
|
||||||
|
if cutoff_date:
|
||||||
|
cutoff_date = cutoff_date + datetime.timedelta(seconds=1)
|
||||||
|
else:
|
||||||
latest_story = MStory.objects(story_feed_id=self.feed.pk).order_by('-story_date').only('story_date').limit(1)
|
latest_story = MStory.objects(story_feed_id=self.feed.pk).order_by('-story_date').only('story_date').limit(1)
|
||||||
if latest_story and len(latest_story) >= 1:
|
if latest_story and len(latest_story) >= 1:
|
||||||
latest_story_date = latest_story[0]['story_date']\
|
cutoff_date = (latest_story[0]['story_date']
|
||||||
+ datetime.timedelta(seconds=1)
|
+ datetime.timedelta(seconds=1))
|
||||||
else:
|
else:
|
||||||
latest_story_date = now
|
cutoff_date = datetime.datetime.utcnow()
|
||||||
|
recount = False
|
||||||
|
|
||||||
self.last_read_date = latest_story_date
|
self.last_read_date = cutoff_date
|
||||||
self.mark_read_date = latest_story_date
|
self.mark_read_date = cutoff_date
|
||||||
|
self.oldest_unread_story_date = cutoff_date
|
||||||
|
if not recount:
|
||||||
self.unread_count_negative = 0
|
self.unread_count_negative = 0
|
||||||
self.unread_count_positive = 0
|
self.unread_count_positive = 0
|
||||||
self.unread_count_neutral = 0
|
self.unread_count_neutral = 0
|
||||||
self.unread_count_updated = now
|
self.unread_count_updated = cutoff_date
|
||||||
self.oldest_unread_story_date = now
|
|
||||||
self.needs_unread_recalc = False
|
self.needs_unread_recalc = False
|
||||||
|
else:
|
||||||
|
self.needs_unread_recalc = True
|
||||||
|
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
|
|
@ -1271,9 +1271,11 @@ def mark_story_as_unread(request):
|
||||||
def mark_feed_as_read(request):
|
def mark_feed_as_read(request):
|
||||||
r = redis.Redis(connection_pool=settings.REDIS_PUBSUB_POOL)
|
r = redis.Redis(connection_pool=settings.REDIS_PUBSUB_POOL)
|
||||||
feed_ids = request.REQUEST.getlist('feed_id')
|
feed_ids = request.REQUEST.getlist('feed_id')
|
||||||
|
cutoff_timestamp = int(request.REQUEST.get('cutoff_timestamp', 0))
|
||||||
multiple = len(feed_ids) > 1
|
multiple = len(feed_ids) > 1
|
||||||
code = 1
|
code = 1
|
||||||
errors = []
|
errors = []
|
||||||
|
cutoff_date = datetime.datetime.fromtimestamp(cutoff_timestamp) if cutoff_timestamp else None
|
||||||
|
|
||||||
for feed_id in feed_ids:
|
for feed_id in feed_ids:
|
||||||
if 'social:' in feed_id:
|
if 'social:' in feed_id:
|
||||||
|
@ -1300,7 +1302,7 @@ def mark_feed_as_read(request):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
marked_read = sub.mark_feed_read()
|
marked_read = sub.mark_feed_read(cutoff_date=cutoff_date)
|
||||||
if marked_read:
|
if marked_read:
|
||||||
r.publish(request.user.username, 'feed:%s' % feed_id)
|
r.publish(request.user.username, 'feed:%s' % feed_id)
|
||||||
except IntegrityError, e:
|
except IntegrityError, e:
|
||||||
|
|
|
@ -245,18 +245,21 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({
|
||||||
}, callback);
|
}, callback);
|
||||||
},
|
},
|
||||||
|
|
||||||
mark_feed_as_read: function(feed_id, callback) {
|
mark_feed_as_read: function(feed_id, cutoff_timestamp, mark_active, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var feed_ids = _.isArray(feed_id)
|
var feed_ids = _.isArray(feed_id)
|
||||||
? _.select(feed_id, function(f) { return f; })
|
? _.select(feed_id, function(f) { return f; })
|
||||||
: [feed_id];
|
: [feed_id];
|
||||||
|
|
||||||
this.make_request('/reader/mark_feed_as_read', {
|
this.make_request('/reader/mark_feed_as_read', {
|
||||||
feed_id: feed_ids
|
feed_id: feed_ids,
|
||||||
|
cutoff_timestamp: cutoff_timestamp
|
||||||
}, callback);
|
}, callback);
|
||||||
|
|
||||||
if (feed_id == NEWSBLUR.reader.active_feed) {
|
if (mark_active) {
|
||||||
this.stories.each(function(story) {
|
this.stories.each(function(story) {
|
||||||
|
if (cutoff_timestamp &&
|
||||||
|
parseInt(story.get('story_timestamp'), 10) > cutoff_timestamp) return;
|
||||||
story.set('read_status', true);
|
story.set('read_status', true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1922,44 +1922,33 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mark_feed_as_read: function(feed_id) {
|
mark_feed_as_read: function(feed_id, days_back) {
|
||||||
feed_id = feed_id || this.active_feed;
|
feed_id = feed_id || this.active_feed;
|
||||||
|
var cutoff_timestamp = NEWSBLUR.utils.days_back_to_timestamp(days_back);
|
||||||
this.model.mark_feed_as_read([feed_id]);
|
if (!days_back && this.model.stories.length &&
|
||||||
this.mark_feed_as_read_update_counts(feed_id);
|
this.model.stories.first().get('story_feed_id') == feed_id &&
|
||||||
|
NEWSBLUR.assets.view_setting(feed_id, 'order') == 'newest') {
|
||||||
if (feed_id == this.active_feed) {
|
cutoff_timestamp = this.model.stories.first().get('story_timestamp');
|
||||||
this.model.stories.each(function(story) {
|
|
||||||
story.set('read_status', true);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.model.mark_feed_as_read([feed_id], cutoff_timestamp, feed_id == this.active_feed, _.bind(function() {
|
||||||
|
this.feeds_unread_count(feed_id);
|
||||||
|
}, this));
|
||||||
},
|
},
|
||||||
|
|
||||||
mark_folder_as_read: function(folder) {
|
mark_folder_as_read: function(folder, days_back) {
|
||||||
var folder = folder || this.active_folder;
|
var folder = folder || this.active_folder;
|
||||||
var feeds = folder.feed_ids_in_folder();
|
var feeds = folder.feed_ids_in_folder();
|
||||||
|
var cutoff_timestamp = NEWSBLUR.utils.days_back_to_timestamp(days_back);
|
||||||
|
if (!days_back && this.model.stories.length &&
|
||||||
|
_.contains(feeds, this.model.stories.first().get('story_feed_id')) &&
|
||||||
|
NEWSBLUR.assets.view_setting(folder.id, 'order') == 'newest') {
|
||||||
|
cutoff_timestamp = this.model.stories.first().get('story_timestamp');
|
||||||
|
}
|
||||||
|
|
||||||
this.model.mark_feed_as_read(feeds);
|
this.model.mark_feed_as_read(feeds, cutoff_timestamp, folder == this.active_folder, _.bind(function() {
|
||||||
_.each(feeds, _.bind(function(feed_id) {
|
this.feeds_unread_count(feeds);
|
||||||
this.mark_feed_as_read_update_counts(feed_id);
|
|
||||||
}, this));
|
}, this));
|
||||||
|
|
||||||
if (folder == this.active_folder) {
|
|
||||||
this.model.stories.each(function(story) {
|
|
||||||
story.set('read_status', true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mark_feed_as_read_update_counts: function(feed_id) {
|
|
||||||
if (feed_id) {
|
|
||||||
var feed = this.model.get_feed(feed_id);
|
|
||||||
if (!feed) return;
|
|
||||||
|
|
||||||
feed.set('ps', 0);
|
|
||||||
feed.set('nt', 0);
|
|
||||||
feed.set('ng', 0);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
open_story_trainer: function(story_id, feed_id, options) {
|
open_story_trainer: function(story_id, feed_id, options) {
|
||||||
|
@ -4150,6 +4139,12 @@
|
||||||
}, this), Math.random() * delay);
|
}, this), Math.random() * delay);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
feeds_unread_count: function(feed_ids, options) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
this.model.feed_unread_count(feed_ids, options.callback);
|
||||||
|
},
|
||||||
|
|
||||||
update_interactions_count: function() {
|
update_interactions_count: function() {
|
||||||
this.model.interactions_count(function(data) {
|
this.model.interactions_count(function(data) {
|
||||||
NEWSBLUR.app.sidebar_header.update_interactions_count(data.interactions_count);
|
NEWSBLUR.app.sidebar_header.update_interactions_count(data.interactions_count);
|
||||||
|
|
|
@ -210,6 +210,13 @@ NEWSBLUR.utils = {
|
||||||
}
|
}
|
||||||
|
|
||||||
return interval;
|
return interval;
|
||||||
|
},
|
||||||
|
|
||||||
|
days_back_to_timestamp: function(days_back) {
|
||||||
|
days_back = days_back || 0;
|
||||||
|
var now = Math.round((new Date()).getTime() / 1000);
|
||||||
|
|
||||||
|
return now - (days_back * 60*60*24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ NEWSBLUR.Views.FeedTitleView = Backbone.View.extend({
|
||||||
"dblclick .feed_counts" : "mark_feed_as_read",
|
"dblclick .feed_counts" : "mark_feed_as_read",
|
||||||
"dblclick" : "open_feed_link",
|
"dblclick" : "open_feed_link",
|
||||||
"click .NB-feedbar-mark-feed-read" : "mark_feed_as_read",
|
"click .NB-feedbar-mark-feed-read" : "mark_feed_as_read",
|
||||||
|
"click .NB-feedbar-mark-feed-read-time" : "mark_feed_as_read_days",
|
||||||
"click .NB-feedbar-mark-feed-read-expand" : "expand_mark_read",
|
"click .NB-feedbar-mark-feed-read-expand" : "expand_mark_read",
|
||||||
"click .NB-feedbar-train-feed" : "open_trainer",
|
"click .NB-feedbar-train-feed" : "open_trainer",
|
||||||
"click .NB-feedbar-statistics" : "open_statistics",
|
"click .NB-feedbar-statistics" : "open_statistics",
|
||||||
|
@ -69,10 +70,10 @@ NEWSBLUR.Views.FeedTitleView = Backbone.View.extend({
|
||||||
<% if (type == "story") { %>\
|
<% if (type == "story") { %>\
|
||||||
<div class="NB-feedbar-mark-feed-read-container">\
|
<div class="NB-feedbar-mark-feed-read-container">\
|
||||||
<div class="NB-feedbar-mark-feed-read"><div class="NB-icon"></div></div>\
|
<div class="NB-feedbar-mark-feed-read"><div class="NB-icon"></div></div>\
|
||||||
<div class="NB-feedbar-mark-feed-read-time NB-1d">1d</div>\
|
<div class="NB-feedbar-mark-feed-read-time" data-days="1">1d</div>\
|
||||||
<div class="NB-feedbar-mark-feed-read-time NB-3d">3d</div>\
|
<div class="NB-feedbar-mark-feed-read-time" data-days="3">3d</div>\
|
||||||
<div class="NB-feedbar-mark-feed-read-time NB-7d">7d</div>\
|
<div class="NB-feedbar-mark-feed-read-time" data-days="7">7d</div>\
|
||||||
<div class="NB-feedbar-mark-feed-read-time NB-14d">14d</div>\
|
<div class="NB-feedbar-mark-feed-read-time" data-days="14">14d</div>\
|
||||||
<div class="NB-feedbar-mark-feed-read-expand"></div>\
|
<div class="NB-feedbar-mark-feed-read-expand"></div>\
|
||||||
</div>\
|
</div>\
|
||||||
<div class="NB-story-title-indicator">\
|
<div class="NB-story-title-indicator">\
|
||||||
|
@ -285,7 +286,7 @@ NEWSBLUR.Views.FeedTitleView = Backbone.View.extend({
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
mark_feed_as_read: function(e) {
|
mark_feed_as_read: function(e, days) {
|
||||||
if (e) {
|
if (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
@ -294,13 +295,18 @@ NEWSBLUR.Views.FeedTitleView = Backbone.View.extend({
|
||||||
_.delay(_.bind(function() {
|
_.delay(_.bind(function() {
|
||||||
this.flags.double_click = false;
|
this.flags.double_click = false;
|
||||||
}, this), 500);
|
}, this), 500);
|
||||||
NEWSBLUR.reader.mark_feed_as_read(this.model.id);
|
NEWSBLUR.reader.mark_feed_as_read(this.model.id, days);
|
||||||
this.$('.NB-feedbar-mark-feed-read-container').fadeOut(400);
|
this.$('.NB-feedbar-mark-feed-read-container').fadeOut(400);
|
||||||
if (e) {
|
if (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mark_feed_as_read_days: function(e) {
|
||||||
|
var days = parseInt($(e.target).data('days'), 10);
|
||||||
|
this.mark_feed_as_read(e, days);
|
||||||
|
},
|
||||||
|
|
||||||
expand_mark_read: function() {
|
expand_mark_read: function() {
|
||||||
var $container = this.$(".NB-feedbar-mark-feed-read-container");
|
var $container = this.$(".NB-feedbar-mark-feed-read-container");
|
||||||
var $markread = this.$(".NB-feedbar-mark-feed-read");
|
var $markread = this.$(".NB-feedbar-mark-feed-read");
|
||||||
|
|
|
@ -17,6 +17,7 @@ NEWSBLUR.Views.Folder = Backbone.View.extend({
|
||||||
"click .NB-feedlist-collapse-icon" : "collapse_folder",
|
"click .NB-feedlist-collapse-icon" : "collapse_folder",
|
||||||
"click .NB-feedbar-mark-feed-read" : "mark_folder_as_read",
|
"click .NB-feedbar-mark-feed-read" : "mark_folder_as_read",
|
||||||
"click .NB-feedbar-mark-feed-read-expand" : "expand_mark_read",
|
"click .NB-feedbar-mark-feed-read-expand" : "expand_mark_read",
|
||||||
|
"click .NB-feedbar-mark-feed-read-time" : "mark_folder_as_read_days",
|
||||||
"click .NB-feedbar-options" : "open_options_popover",
|
"click .NB-feedbar-options" : "open_options_popover",
|
||||||
"click .NB-story-title-indicator" : "show_hidden_story_titles",
|
"click .NB-story-title-indicator" : "show_hidden_story_titles",
|
||||||
"mouseenter" : "add_hover_inverse",
|
"mouseenter" : "add_hover_inverse",
|
||||||
|
@ -106,10 +107,10 @@ NEWSBLUR.Views.Folder = Backbone.View.extend({
|
||||||
<% if (feedbar) { %>\
|
<% if (feedbar) { %>\
|
||||||
<div class="NB-feedbar-mark-feed-read-container">\
|
<div class="NB-feedbar-mark-feed-read-container">\
|
||||||
<div class="NB-feedbar-mark-feed-read"><div class="NB-icon"></div></div>\
|
<div class="NB-feedbar-mark-feed-read"><div class="NB-icon"></div></div>\
|
||||||
<div class="NB-feedbar-mark-feed-read-time NB-1d">1d</div>\
|
<div class="NB-feedbar-mark-feed-read-time" data-days="1">1d</div>\
|
||||||
<div class="NB-feedbar-mark-feed-read-time NB-3d">3d</div>\
|
<div class="NB-feedbar-mark-feed-read-time" data-days="3">3d</div>\
|
||||||
<div class="NB-feedbar-mark-feed-read-time NB-7d">7d</div>\
|
<div class="NB-feedbar-mark-feed-read-time" data-days="7">7d</div>\
|
||||||
<div class="NB-feedbar-mark-feed-read-time NB-14d">14d</div>\
|
<div class="NB-feedbar-mark-feed-read-time" data-days="14">14d</div>\
|
||||||
<div class="NB-feedbar-mark-feed-read-expand"></div>\
|
<div class="NB-feedbar-mark-feed-read-expand"></div>\
|
||||||
</div>\
|
</div>\
|
||||||
<div class="NB-story-title-indicator">\
|
<div class="NB-story-title-indicator">\
|
||||||
|
@ -360,11 +361,16 @@ NEWSBLUR.Views.Folder = Backbone.View.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mark_folder_as_read: function() {
|
mark_folder_as_read: function(days_back) {
|
||||||
NEWSBLUR.reader.mark_folder_as_read();
|
NEWSBLUR.reader.mark_folder_as_read(this.model, days_back);
|
||||||
this.$('.NB-feedbar-mark-feed-read').fadeOut(400);
|
this.$('.NB-feedbar-mark-feed-read').fadeOut(400);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mark_folder_as_read_days: function(e) {
|
||||||
|
var days = parseInt($(e.target).data('days'), 10);
|
||||||
|
this.mark_folder_as_read(days);
|
||||||
|
},
|
||||||
|
|
||||||
expand_mark_read: function() {
|
expand_mark_read: function() {
|
||||||
NEWSBLUR.Views.FeedTitleView.prototype.expand_mark_read.call(this);
|
NEWSBLUR.Views.FeedTitleView.prototype.expand_mark_read.call(this);
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Reference in a new issue