mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-09-18 21:50:56 +00:00
A whopper: marking stories as read in a social feed.
This commit is contained in:
parent
4fb275ccfc
commit
193201061e
8 changed files with 190 additions and 112 deletions
|
@ -373,14 +373,15 @@ class MUserStory(mongo.Document):
|
|||
user_id = mongo.IntField()
|
||||
feed_id = mongo.IntField()
|
||||
read_date = mongo.DateTimeField()
|
||||
story_id = mongo.StringField()
|
||||
story_id = mongo.StringField(unique_with=('user_id', 'feed_id'))
|
||||
story_date = mongo.DateTimeField()
|
||||
story = mongo.ReferenceField(MStory, unique_with=('user_id', 'feed_id'))
|
||||
story = mongo.ReferenceField(MStory)
|
||||
|
||||
meta = {
|
||||
'collection': 'userstories',
|
||||
'indexes': [('user_id', 'feed_id'), ('feed_id', 'read_date'), ('feed_id', 'story_id')],
|
||||
'allow_inheritance': False,
|
||||
'index_drop_dups': True,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -19,6 +19,7 @@ urlpatterns = patterns('',
|
|||
url(r'^mark_all_as_read', views.mark_all_as_read, name='mark-all-as-read'),
|
||||
url(r'^mark_story_as_read', views.mark_story_as_read, name='mark-story-as-read'),
|
||||
url(r'^mark_feed_stories_as_read', views.mark_feed_stories_as_read, name='mark-feed-stories-as-read'),
|
||||
url(r'^mark_social_stories_as_read', views.mark_social_stories_as_read, name='mark-social-stories-as-read'),
|
||||
url(r'^mark_story_as_unread', views.mark_story_as_unread),
|
||||
url(r'^mark_story_as_starred', views.mark_story_as_starred),
|
||||
url(r'^mark_story_as_unstarred', views.mark_story_as_unstarred),
|
||||
|
|
|
@ -704,7 +704,6 @@ def mark_all_as_read(request):
|
|||
def mark_story_as_read(request):
|
||||
story_ids = request.REQUEST.getlist('story_id')
|
||||
feed_id = int(get_argument_or_404(request, 'feed_id'))
|
||||
usersub = None
|
||||
|
||||
try:
|
||||
usersub = UserSubscription.objects.select_related('feed').get(user=request.user, feed=feed_id)
|
||||
|
@ -716,17 +715,16 @@ def mark_story_as_read(request):
|
|||
usersub = UserSubscription.objects.get(user=request.user,
|
||||
feed=duplicate_feed[0].feed)
|
||||
except (Feed.DoesNotExist):
|
||||
return dict(code=-1)
|
||||
return dict(code=-1, errors=["No feed exists for feed_id %d." % feed_id])
|
||||
else:
|
||||
return dict(code=-1)
|
||||
return dict(code=-1, errors=["No feed exists for feed_id %d." % feed_id])
|
||||
except UserSubscription.DoesNotExist:
|
||||
pass
|
||||
usersub = None
|
||||
|
||||
if usersub:
|
||||
data = usersub.mark_story_ids_as_read(story_ids, request=request)
|
||||
else:
|
||||
socialsub = MSocialSubscription.objects.get(user_id=request.user.pk, subscription_user_id=feed_id)
|
||||
data = socialsub.mark_story_ids_as_read(story_ids, request=request)
|
||||
data = dict(code=-1, errors=["User is not subscribed to this feed."])
|
||||
|
||||
return data
|
||||
|
||||
|
@ -739,19 +737,54 @@ def mark_feed_stories_as_read(request):
|
|||
feed_id = int(feed_id)
|
||||
try:
|
||||
usersub = UserSubscription.objects.select_related('feed').get(user=request.user, feed=feed_id)
|
||||
except (UserSubscription.DoesNotExist, Feed.DoesNotExist):
|
||||
data = usersub.mark_story_ids_as_read(story_ids)
|
||||
except UserSubscription.DoesNotExist:
|
||||
return dict(code=-1, error="You are not subscribed to this feed_id: %d" % feed_id)
|
||||
except Feed.DoesNotExist:
|
||||
duplicate_feed = DuplicateFeed.objects.filter(duplicate_feed_id=feed_id)
|
||||
if duplicate_feed:
|
||||
try:
|
||||
usersub = UserSubscription.objects.get(user=request.user,
|
||||
feed=duplicate_feed[0].feed)
|
||||
except (UserSubscription.DoesNotExist, Feed.DoesNotExist):
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
usersub.mark_story_ids_as_read(story_ids)
|
||||
try:
|
||||
if not duplicate_feed: raise Feed.DoesNotExist
|
||||
usersub = UserSubscription.objects.get(user=request.user,
|
||||
feed=duplicate_feed[0].feed)
|
||||
data = usersub.mark_story_ids_as_read(story_ids)
|
||||
except (UserSubscription.DoesNotExist, Feed.DoesNotExist):
|
||||
return dict(code=-1, error="No feed exists for feed_id: %d" % feed_id)
|
||||
|
||||
return dict(code=1)
|
||||
return data
|
||||
|
||||
@ajax_login_required
|
||||
@json.json_view
|
||||
def mark_social_stories_as_read(request):
|
||||
code = 1
|
||||
errors = []
|
||||
data = None
|
||||
users_feeds_stories = request.REQUEST.get('users_feeds_stories', "{}")
|
||||
users_feeds_stories = json.decode(users_feeds_stories)
|
||||
|
||||
for social_user_id, feeds in users_feeds_stories.items():
|
||||
for feed_id, story_ids in feeds.items():
|
||||
feed_id = int(feed_id)
|
||||
try:
|
||||
print social_user_id, feed_id
|
||||
socialsub = MSocialSubscription.objects.get(user_id=request.user.pk,
|
||||
subscription_user_id=social_user_id)
|
||||
data = socialsub.mark_story_ids_as_read(story_ids, feed_id, request=request)
|
||||
except MSocialSubscription.DoesNotExist:
|
||||
errors.append("You are not subscribed to this social user_id: %s" % social_user_id)
|
||||
except Feed.DoesNotExist:
|
||||
duplicate_feed = DuplicateFeed.objects.filter(duplicate_feed_id=feed_id)
|
||||
if duplicate_feed:
|
||||
try:
|
||||
socialsub = MSocialSubscription.objects.get(user_id=request.user.pk,
|
||||
subscription_user_id=social_user_id)
|
||||
data = socialsub.mark_story_ids_as_read(story_ids, duplicate_feed[0].feed.pk, request=request)
|
||||
except (UserSubscription.DoesNotExist, Feed.DoesNotExist):
|
||||
code = -1
|
||||
errors.append("No feed exists for feed_id %d." % feed_id)
|
||||
else:
|
||||
continue
|
||||
|
||||
return dict(code=code, errors=errors, data=data)
|
||||
|
||||
@ajax_login_required
|
||||
@json.json_view
|
||||
|
|
|
@ -259,7 +259,7 @@ class MSocialSubscription(mongo.Document):
|
|||
'is_trained': self.is_trained,
|
||||
}
|
||||
|
||||
def mark_story_ids_as_read(self, story_ids, request=None):
|
||||
def mark_story_ids_as_read(self, story_ids, feed_id, request=None):
|
||||
data = dict(code=0, payload=story_ids)
|
||||
|
||||
if not request:
|
||||
|
@ -278,8 +278,8 @@ class MSocialSubscription(mongo.Document):
|
|||
story = MSharedStory.objects.get(user_id=self.subscription_user_id, story_guid=story_id)
|
||||
now = datetime.datetime.utcnow()
|
||||
date = now if now > story.story_date else story.story_date # For handling future stories
|
||||
m = MUserStory(story=story, user_id=self.user_id,
|
||||
feed_id=self.feed_id, read_date=date,
|
||||
m = MUserStory(user_id=self.user_id,
|
||||
feed_id=feed_id, read_date=date,
|
||||
story_id=story_id, story_date=story.story_date)
|
||||
m.save()
|
||||
|
||||
|
|
|
@ -25,62 +25,6 @@ from vendor import facebook
|
|||
from vendor import tweepy
|
||||
from vendor.timezones.utilities import localtime_for_timezone
|
||||
|
||||
@json.json_view
|
||||
def story_comments(request):
|
||||
feed_id = int(request.POST['feed_id'])
|
||||
story_id = request.POST['story_id']
|
||||
full = request.POST.get('full', False)
|
||||
compact = request.POST.get('compact', False)
|
||||
|
||||
shared_stories = MSharedStory.objects.filter(story_feed_id=feed_id, story_guid=story_id)
|
||||
comments = [s.comments_with_author(compact=compact, full=full) for s in shared_stories]
|
||||
|
||||
return {'comments': comments}
|
||||
|
||||
@ajax_login_required
|
||||
@json.json_view
|
||||
def mark_story_as_shared(request):
|
||||
code = 1
|
||||
feed_id = int(request.POST['feed_id'])
|
||||
story_id = request.POST['story_id']
|
||||
comments = request.POST.get('comments', '')
|
||||
|
||||
story = MStory.objects(story_feed_id=feed_id, story_guid=story_id).limit(1).first()
|
||||
if not story:
|
||||
return {'code': -1, 'message': 'Story not found.'}
|
||||
|
||||
shared_story = MSharedStory.objects.filter(user_id=request.user.pk, story_feed_id=feed_id, story_guid=story_id)
|
||||
if not shared_story:
|
||||
story_db = dict([(k, v) for k, v in story._data.items()
|
||||
if k is not None and v is not None])
|
||||
story_values = dict(user_id=request.user.pk, comments=comments,
|
||||
has_comments=bool(comments), **story_db)
|
||||
MSharedStory.objects.create(**story_values)
|
||||
logging.user(request, "~FCSharing: ~SB~FM%s (~FB%s~FM)" % (story.story_title[:50], comments[:100]))
|
||||
else:
|
||||
shared_story = shared_story[0]
|
||||
shared_story.comments = comments
|
||||
shared_story.has_comments = bool(comments)
|
||||
shared_story.save()
|
||||
logging.user(request, "~FCUpdating shared story: ~SB~FM%s (~FB%s~FM)" % (story.story_title[:50], comments[:100]))
|
||||
|
||||
story.count_comments()
|
||||
|
||||
story = Feed.format_story(story)
|
||||
story = MSharedStory.stories_with_comments([story], request.user)[0]
|
||||
|
||||
return {'code': code, 'story': story}
|
||||
|
||||
def shared_stories_public(request, username):
|
||||
try:
|
||||
user = User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
shared_stories = MSharedStory.objects.filter(user_id=user.pk)
|
||||
|
||||
return HttpResponse("There are %s stories shared by %s." % (shared_stories.count(), username))
|
||||
|
||||
@json.json_view
|
||||
def load_social_stories(request, user_id, username=None):
|
||||
user = get_user(request)
|
||||
|
@ -99,8 +43,8 @@ def load_social_stories(request, user_id, username=None):
|
|||
return dict(stories=[])
|
||||
|
||||
stories = MSharedStory.stories_with_comments(stories, user, check_all=True)
|
||||
story_feed_ids = list(set(s['story_feed_id'] for s in stories))
|
||||
|
||||
story_feed_ids = list(set(s['story_feed_id'] for s in stories))
|
||||
socialsub = MSocialSubscription.objects.get(user_id=user.pk, subscription_user_id=social_user_id)
|
||||
usersubs = UserSubscription.objects.filter(user__pk=user.pk, feed__pk__in=story_feed_ids)
|
||||
usersubs_map = dict((sub.feed_id, sub) for sub in usersubs)
|
||||
|
@ -132,6 +76,7 @@ def load_social_stories(request, user_id, username=None):
|
|||
userstories = set(us.story_id for us in userstories_db)
|
||||
|
||||
for story in stories:
|
||||
story['social_user_id'] = social_user_id
|
||||
story_feed_id = story['story_feed_id']
|
||||
story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date, now)
|
||||
|
@ -204,6 +149,62 @@ def load_social_page(request, user_id, username=None):
|
|||
|
||||
return params
|
||||
|
||||
@json.json_view
|
||||
def story_comments(request):
|
||||
feed_id = int(request.POST['feed_id'])
|
||||
story_id = request.POST['story_id']
|
||||
full = request.POST.get('full', False)
|
||||
compact = request.POST.get('compact', False)
|
||||
|
||||
shared_stories = MSharedStory.objects.filter(story_feed_id=feed_id, story_guid=story_id)
|
||||
comments = [s.comments_with_author(compact=compact, full=full) for s in shared_stories]
|
||||
|
||||
return {'comments': comments}
|
||||
|
||||
@ajax_login_required
|
||||
@json.json_view
|
||||
def mark_story_as_shared(request):
|
||||
code = 1
|
||||
feed_id = int(request.POST['feed_id'])
|
||||
story_id = request.POST['story_id']
|
||||
comments = request.POST.get('comments', '')
|
||||
|
||||
story = MStory.objects(story_feed_id=feed_id, story_guid=story_id).limit(1).first()
|
||||
if not story:
|
||||
return {'code': -1, 'message': 'Story not found.'}
|
||||
|
||||
shared_story = MSharedStory.objects.filter(user_id=request.user.pk, story_feed_id=feed_id, story_guid=story_id)
|
||||
if not shared_story:
|
||||
story_db = dict([(k, v) for k, v in story._data.items()
|
||||
if k is not None and v is not None])
|
||||
story_values = dict(user_id=request.user.pk, comments=comments,
|
||||
has_comments=bool(comments), **story_db)
|
||||
MSharedStory.objects.create(**story_values)
|
||||
logging.user(request, "~FCSharing: ~SB~FM%s (~FB%s~FM)" % (story.story_title[:50], comments[:100]))
|
||||
else:
|
||||
shared_story = shared_story[0]
|
||||
shared_story.comments = comments
|
||||
shared_story.has_comments = bool(comments)
|
||||
shared_story.save()
|
||||
logging.user(request, "~FCUpdating shared story: ~SB~FM%s (~FB%s~FM)" % (story.story_title[:50], comments[:100]))
|
||||
|
||||
story.count_comments()
|
||||
|
||||
story = Feed.format_story(story)
|
||||
story = MSharedStory.stories_with_comments([story], request.user)[0]
|
||||
|
||||
return {'code': code, 'story': story}
|
||||
|
||||
def shared_stories_public(request, username):
|
||||
try:
|
||||
user = User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
shared_stories = MSharedStory.objects.filter(user_id=user.pk)
|
||||
|
||||
return HttpResponse("There are %s stories shared by %s." % (shared_stories.count(), username))
|
||||
|
||||
@json.json_view
|
||||
def friends(request):
|
||||
user = get_user(request)
|
||||
|
@ -272,7 +273,8 @@ def shared_stories_rss_feed(request, user_id, username):
|
|||
raise Http404
|
||||
|
||||
if user.username != username:
|
||||
return HttpResponseRedirect(reverse('shared-story-feed', kwargs={'username': user.username, 'user_id': user.pk}))
|
||||
params = {'username': user.username, 'user_id': user.pk}
|
||||
return HttpResponseRedirect(reverse('shared-stories-rss-feed', kwargs=params))
|
||||
|
||||
social_profile = MSocialProfile.objects.get(user_id=user_id)
|
||||
|
||||
|
|
|
@ -46,11 +46,14 @@ NEWSBLUR.AssetModel.Reader.prototype = {
|
|||
|
||||
init: function() {
|
||||
this.ajax = {};
|
||||
this.ajax['queue'] = $.manageAjax.create('queue', {queue: true});
|
||||
this.ajax['queue'] = $.manageAjax.create('queue', {queue: true});
|
||||
this.ajax['queue_clear'] = $.manageAjax.create('queue_clear', {queue: 'clear'});
|
||||
this.ajax['feed'] = $.manageAjax.create('feed', {queue: 'clear', abortOld: true, domCompleteTrigger: true});
|
||||
this.ajax['feed_page'] = $.manageAjax.create('feed_page', {queue: 'clear', abortOld: true, abortIsNoSuccess: false, domCompleteTrigger: true});
|
||||
this.ajax['statistics'] = $.manageAjax.create('statistics', {queue: 'clear', abortOld: true});
|
||||
this.ajax['feed'] = $.manageAjax.create('feed', {queue: 'clear', abortOld: true,
|
||||
domCompleteTrigger: true});
|
||||
this.ajax['feed_page'] = $.manageAjax.create('feed_page', {queue: 'clear', abortOld: true,
|
||||
abortIsNoSuccess: false,
|
||||
domCompleteTrigger: true});
|
||||
this.ajax['statistics'] = $.manageAjax.create('statistics', {queue: 'clear', abortOld: true});
|
||||
$.ajaxSettings.traditional = true;
|
||||
return;
|
||||
},
|
||||
|
@ -119,30 +122,64 @@ NEWSBLUR.AssetModel.Reader.prototype = {
|
|||
|
||||
mark_story_as_read: function(story_id, feed_id, callback) {
|
||||
var self = this;
|
||||
var read = false;
|
||||
|
||||
var story = this.get_story(story_id);
|
||||
read = story.read_status;
|
||||
story.read_status = 1;
|
||||
|
||||
if (!read && NEWSBLUR.Globals.is_authenticated) {
|
||||
if (!(feed_id in this.queued_read_stories)) { this.queued_read_stories[feed_id] = []; }
|
||||
this.queued_read_stories[feed_id].push(story_id);
|
||||
// NEWSBLUR.log(['Marking Read', this.queued_read_stories, story_id]);
|
||||
if (!story.read_status) {
|
||||
story.read_status = 1;
|
||||
|
||||
this.make_request('/reader/mark_story_as_read', {
|
||||
story_id: this.queued_read_stories[feed_id],
|
||||
feed_id: feed_id
|
||||
}, null, null, {
|
||||
'ajax_group': 'queue_clear',
|
||||
'beforeSend': function() {
|
||||
self.queued_read_stories[feed_id] = [];
|
||||
}
|
||||
});
|
||||
if (NEWSBLUR.Globals.is_authenticated) {
|
||||
if (!(feed_id in this.queued_read_stories)) { this.queued_read_stories[feed_id] = []; }
|
||||
this.queued_read_stories[feed_id].push(story_id);
|
||||
// NEWSBLUR.log(['Marking Read', this.queued_read_stories, story_id]);
|
||||
|
||||
this.make_request('/reader/mark_story_as_read', {
|
||||
story_id: this.queued_read_stories[feed_id],
|
||||
feed_id: feed_id
|
||||
}, null, null, {
|
||||
'ajax_group': 'queue_clear',
|
||||
'beforeSend': function() {
|
||||
self.queued_read_stories = {};
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.read_stories_river_count += 1;
|
||||
$.isFunction(callback) && callback(read);
|
||||
$.isFunction(callback) && callback();
|
||||
},
|
||||
|
||||
mark_social_story_as_read: function(story_id, social_feed_id, callback) {
|
||||
var self = this;
|
||||
var story = this.get_story(story_id);
|
||||
var feed_id = story.story_feed_id;
|
||||
var social_user_id = this.social_feeds[social_feed_id].user_id;
|
||||
|
||||
if (!story.read_status) {
|
||||
story.read_status = 1;
|
||||
|
||||
if (NEWSBLUR.Globals.is_authenticated) {
|
||||
if (!(social_user_id in this.queued_read_stories)) {
|
||||
this.queued_read_stories[social_user_id] = {};
|
||||
}
|
||||
if (!(feed_id in this.queued_read_stories[social_user_id])) {
|
||||
this.queued_read_stories[social_user_id][feed_id] = [];
|
||||
}
|
||||
this.queued_read_stories[social_user_id][feed_id].push(story_id);
|
||||
// NEWSBLUR.log(['Marking Read', this.queued_read_stories, story_id]);
|
||||
|
||||
this.make_request('/reader/mark_social_stories_as_read', {
|
||||
users_feeds_stories: $.toJSON(this.queued_read_stories)
|
||||
}, null, null, {
|
||||
'ajax_group': 'queue_clear',
|
||||
'beforeSend': function() {
|
||||
self.queued_read_stories = {};
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.read_stories_river_count += 1;
|
||||
$.isFunction(callback) && callback();
|
||||
},
|
||||
|
||||
mark_story_as_unread: function(story_id, feed_id, callback) {
|
||||
|
|
|
@ -662,7 +662,6 @@
|
|||
if ($story && $story.length) {
|
||||
// Check for NB-mark above and use that.
|
||||
if ($story.closest('.NB-mark').length) {
|
||||
console.log(["NB-mark", $story, $story.closest('.NB-mark')]);
|
||||
$story = $story.closest('.NB-mark');
|
||||
}
|
||||
|
||||
|
@ -1119,9 +1118,11 @@
|
|||
},
|
||||
|
||||
load_router: function() {
|
||||
NEWSBLUR.router = new NEWSBLUR.Router;
|
||||
var route_found = Backbone.history.start({pushState: true});
|
||||
this.load_url_next_param(route_found);
|
||||
if (!NEWSBLUR.router) {
|
||||
NEWSBLUR.router = new NEWSBLUR.Router;
|
||||
var route_found = Backbone.history.start({pushState: true});
|
||||
this.load_url_next_param(route_found);
|
||||
}
|
||||
},
|
||||
|
||||
make_feed_favicons: function() {
|
||||
|
@ -2624,10 +2625,13 @@
|
|||
|
||||
mark_story_as_read: function(story_id) {
|
||||
var self = this;
|
||||
var $story_title = this.find_story_in_story_titles(story_id);
|
||||
var feed_id = parseInt($story_title.data('feed_id'), 10) || this.active_feed;
|
||||
var feed_id = this.active_feed;
|
||||
|
||||
this.model.mark_story_as_read(story_id, feed_id, function(read) {
|
||||
var mark_read_fn = this.model.mark_story_as_read;
|
||||
if (this.flags.social_view) {
|
||||
mark_read_fn = this.model.mark_social_story_as_read;
|
||||
}
|
||||
mark_read_fn.call(this.model, story_id, feed_id, function(read) {
|
||||
self.update_read_count(story_id, feed_id, false, read);
|
||||
});
|
||||
},
|
||||
|
@ -7248,7 +7252,7 @@
|
|||
this.check_feed_view_scrolled_to_bottom();
|
||||
}
|
||||
|
||||
if (this.flags.river_view &&
|
||||
if ((this.flags.river_view || this.flags.social_view) &&
|
||||
!this.model.preference('feed_view_single_story')) {
|
||||
var story;
|
||||
if (this.flags.scrolling_by_selecting_story_title) {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
<head>
|
||||
<title>{{ social_profile.feed_title }}</title>
|
||||
<link rel="alternate" type="application/rss+xml" href="{% url shared-story-feed user.pk user.username %}" title="{{ social_profile.feed_title }} RSS feed">
|
||||
<link rel="alternate" type="application/rss+xml" href="{% url shared-stories-rss-feed user.pk user.username %}" title="{{ social_profile.feed_title }} RSS feed">
|
||||
<link rel="shortcut icon" HREF="{{ social_profile.photo_url }}">
|
||||
<link rel="stylesheet" href="{{ MEDIA_URL }}css/social/social_page.css" type="text/css" media="screen" title="no title" charset="utf-8">
|
||||
{% if social_profile.custom_css %}
|
||||
|
@ -18,7 +18,7 @@
|
|||
<header class="NB-header">
|
||||
<h1 class="NB-title">{{ social_profile.feed_title }}</h1>
|
||||
<div class="NB-header-feed">
|
||||
<a type="application/rss+xml" href="{% url shared-story-feed user.pk user.username %}">RSS feed for this page</a>
|
||||
<a type="application/rss+xml" href="{% url shared-stories-rss-feed user.pk user.username %}">RSS feed for this page</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue