Stars now save to the new StarredStory mongo model. THey are also persistent on the client-side. Now to just make a special starred stories view and counter.

This commit is contained in:
Samuel Clay 2010-11-30 10:30:18 -05:00
parent 316010882a
commit 4507f7286a
6 changed files with 126 additions and 24 deletions

View file

@ -14,6 +14,8 @@ urlpatterns = patterns('',
url(r'^refresh_feeds', views.refresh_feeds, name='refresh-feeds'),
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),
url(r'^mark_story_as_starred', views.mark_story_as_starred),
url(r'^mark_story_as_unstarred', views.mark_story_as_unstarred),
url(r'^mark_feed_as_read', views.mark_feed_as_read),
url(r'^delete_feed', views.delete_feed, name='delete-feed'),
url(r'^delete_folder', views.delete_folder, name='delete-folder'),

View file

@ -20,7 +20,7 @@ from apps.analyzer.models import get_classifiers_for_user
from apps.reader.models import UserSubscription, UserSubscriptionFolders, MUserStory, Feature
from apps.reader.forms import SignupForm, LoginForm, FeatureForm
try:
from apps.rss_feeds.models import Feed, MFeedPage, DuplicateFeed, MStory, FeedLoadtime
from apps.rss_feeds.models import Feed, MFeedPage, DuplicateFeed, MStory, MStarredStory, FeedLoadtime
except:
pass
from utils import json_functions as json, urlnorm
@ -291,6 +291,9 @@ def load_single_feed(request):
userstories_db = MUserStory.objects(user_id=user.pk,
feed_id=feed.pk,
read_date__gte=usersub.mark_read_date)
starred_stories = MStarredStory.objects(user_id=request.user.pk, story_feed_id=feed_id).only('story_guid')
starred_stories = [story.story_guid for story in starred_stories]
for us in userstories_db:
if hasattr(us.story, 'story_guid') and isinstance(us.story.story_guid, unicode):
userstories.append(us.story.story_guid)
@ -311,6 +314,8 @@ def load_single_feed(request):
story['read_status'] = 1
elif not story.get('read_status') and story['story_date'] > usersub.last_read_date:
story['read_status'] = 0
if story['id'] in starred_stories:
story['starred'] = True
story['intelligence'] = {
'feed': apply_classifier_feeds(classifier_feeds, feed),
'author': apply_classifier_authors(classifier_authors, story),
@ -715,4 +720,37 @@ def login_as(request):
def iframe_buster(request):
logging.info(" ---> [%s] iFrame bust!" % (request.user,))
return HttpResponse(status=204)
return HttpResponse(status=204)
@ajax_login_required
@json.json_view
def mark_story_as_starred(request):
code = 1
feed_id = int(request.POST['feed_id'])
story_id = request.POST['story_id']
story = MStory.objects(story_feed_id=feed_id, story_guid=story_id).limit(1)
if story:
story_db = dict([(k, v) for k, v in story[0]._data.items()
if k is not None and v is not None])
story_values = dict(user_id=request.user.pk, **story_db)
MStarredStory.objects.create(**story_values)
else:
code = -1
return {'code': code}
@ajax_login_required
@json.json_view
def mark_story_as_unstarred(request):
code = 1
feed_id = int(request.POST['feed_id'])
story_id = request.POST['story_id']
starred_story = MStarredStory.objects(user_id=request.user.pk, story_guid=story_id, story_feed_id=feed_id)
if starred_story:
starred_story.delete()
else:
code = -1
return {'code': code}

View file

@ -761,20 +761,22 @@ class Story(models.Model):
self.story_title = self.story_title[:255]
super(Story, self).save(*args, **kwargs)
class MStory(mongo.Document):
'''A feed item'''
story_feed_id = mongo.IntField()
story_date = mongo.DateTimeField()
story_title = mongo.StringField(max_length=1024)
story_content = mongo.StringField()
story_content_z = mongo.BinaryField()
story_original_content = mongo.StringField()
story_feed_id = mongo.IntField()
story_date = mongo.DateTimeField()
story_title = mongo.StringField(max_length=1024)
story_content = mongo.StringField()
story_content_z = mongo.BinaryField()
story_original_content = mongo.StringField()
story_original_content_z = mongo.BinaryField()
story_content_type = mongo.StringField(max_length=255)
story_author_name = mongo.StringField()
story_permalink = mongo.StringField()
story_guid = mongo.StringField()
story_tags = mongo.ListField(mongo.StringField(max_length=250))
story_content_type = mongo.StringField(max_length=255)
story_author_name = mongo.StringField()
story_permalink = mongo.StringField()
story_guid = mongo.StringField()
story_tags = mongo.ListField(mongo.StringField(max_length=250))
meta = {
'collection': 'stories',
@ -791,7 +793,42 @@ class MStory(mongo.Document):
self.story_original_content_z = zlib.compress(self.story_original_content)
self.story_original_content = None
super(MStory, self).save(*args, **kwargs)
class MStarredStory(mongo.Document):
"""Like MStory, but not inherited due to large overhead of _cls and _type in
mongoengine's inheritance model on every single row."""
user_id = mongo.IntField()
story_feed_id = mongo.IntField()
story_date = mongo.DateTimeField()
story_title = mongo.StringField(max_length=1024)
story_content = mongo.StringField()
story_content_z = mongo.BinaryField()
story_original_content = mongo.StringField()
story_original_content_z = mongo.BinaryField()
story_content_type = mongo.StringField(max_length=255)
story_author_name = mongo.StringField()
story_permalink = mongo.StringField()
story_guid = mongo.StringField(unique_with=('user_id',))
story_tags = mongo.ListField(mongo.StringField(max_length=250))
meta = {
'collection': 'starred_stories',
'indexes': [('user_id', '-story_date'), 'story_feed_id'],
'ordering': ['-story_date'],
'allow_inheritance': False,
}
def save(self, *args, **kwargs):
if self.story_content:
self.story_content_z = zlib.compress(self.story_content)
self.story_content = None
if self.story_original_content:
self.story_original_content_z = zlib.compress(self.story_original_content)
self.story_original_content = None
super(MStarredStory, self).save(*args, **kwargs)
class FeedUpdateHistory(models.Model):
fetch_date = models.DateTimeField(auto_now=True)
number_of_feeds = models.IntegerField()
@ -809,6 +846,7 @@ class FeedUpdateHistory(models.Model):
self.average_per_feed = str(self.seconds_taken / float(max(1.0,self.number_of_feeds)))
super(FeedUpdateHistory, self).save(*args, **kwargs)
class FeedFetchHistory(models.Model):
feed = models.ForeignKey(Feed, related_name='feed_fetch_history')
status_code = models.CharField(max_length=10, null=True, blank=True)
@ -826,6 +864,7 @@ class FeedFetchHistory(models.Model):
self.exception and self.exception[:50]
)
class MFeedFetchHistory(mongo.Document):
feed_id = mongo.IntField()
status_code = mongo.IntField()
@ -844,6 +883,7 @@ class MFeedFetchHistory(mongo.Document):
self.exception = unicode(self.exception)
super(MFeedFetchHistory, self).save(*args, **kwargs)
class PageFetchHistory(models.Model):
feed = models.ForeignKey(Feed, related_name='page_fetch_history')
status_code = models.CharField(max_length=10, null=True, blank=True)
@ -861,6 +901,7 @@ class PageFetchHistory(models.Model):
self.exception and self.exception[:50]
)
class MPageFetchHistory(mongo.Document):
feed_id = mongo.IntField()
status_code = mongo.IntField()

View file

@ -1056,8 +1056,10 @@ background: transparent;
background: transparent url('../img/reader/star_blue.png') no-repeat 4px 0px;
opacity: .25;
}
#story_titles .NB-story-star:hover {
#story_titles .NB-story-star:hover,
#story_titles .NB-story-starred .NB-story-star {
opacity: 1;
display: block;
}
#story_titles .story.read {

View file

@ -21,6 +21,7 @@ NEWSBLUR.AssetModel.Reader = function() {
this.stories = {};
this.read_stories = {};
this.classifiers = {};
this.starred_stories = [];
this.DEFAULT_VIEW = NEWSBLUR.Preferences.default_view || 'page';
};
@ -122,17 +123,23 @@ NEWSBLUR.AssetModel.Reader.prototype = {
$.isFunction(callback) && callback(read);
},
mark_story_as_starred: function(story_id, feed_id, callback) {
var self = this;
this.make_request('/reader/mark_story_as_starred', {
story_id: story_id,
feed_id: feed_id
}, callback);
},
mark_feed_as_read: function(feed_id, callback) {
var self = this;
var feed_ids = _.isArray(feed_id)
? _.select(feed_id, function(f) { return f; })
: [feed_id];
this.make_request('/reader/mark_feed_as_read',
{
feed_id: feed_ids
}, callback
);
this.make_request('/reader/mark_feed_as_read', {
feed_id: feed_ids
}, callback);
},
load_feeds: function(callback, error_callback) {
@ -191,6 +198,7 @@ NEWSBLUR.AssetModel.Reader.prototype = {
this.feed_authors = data.feed_authors;
this.feed_id = feed_id;
this.classifiers = data.classifiers;
this.starred_stories = data.starred_stories;
this.story_keys = [];
for (var s in data.stories) {
this.story_keys.push(data.stories[s].id);

View file

@ -1697,6 +1697,16 @@
NEWSBLUR.classifier = new NEWSBLUR.ReaderClassifierStory(story_id, feed_id, {'score': -1});
},
mark_story_as_starred: function(story_id, $button) {
// $button.attr({'title': 'Saving...'});
$button.tipsy({'title': 'Saving...'});
$button.closest('.story').addClass('NB-story-starred');
this.model.mark_story_as_starred(story_id, this.active_feed, function() {
// $button.attr({'title': 'Saved!'});
$button.tipsy({'title': 'Saved!'});
});
},
// =====================
// = Story Titles Pane =
// =====================
@ -1745,10 +1755,11 @@
make_story_title: function(story) {
var unread_view = this.model.preference('unread_view');
var read = story.read_status
? 'read'
? ' read '
: '';
var score = this.compute_story_score(story);
var score_color = 'neutral';
var starred = story.starred ? ' NB-story-starred ' : '';
if (score > 0) score_color = 'positive';
if (score < 0) score_color = 'negative';
var $story_tags = $.make('span', { className: 'NB-storytitles-tags'});
@ -1759,7 +1770,7 @@
$story_tags.append($tag);
break;
}
var $story_title = $.make('div', { className: 'story ' + read + ' NB-story-' + score_color }, [
var $story_title = $.make('div', { className: 'story' + read + starred + 'NB-story-' + score_color }, [
$.make('a', { href: story.story_permalink, className: 'story_title' }, [
$.make('span', { className: 'NB-storytitles-title' }, story.story_title),
$.make('span', { className: 'NB-storytitles-author' }, story.story_authors),
@ -3498,10 +3509,10 @@
self.mark_story_as_like(story_id, $t);
story_prevent_bubbling = true;
});
$.targetIs(e, { tagSelector: '.NB-story-dislike' }, function($t, $p){
$.targetIs(e, { tagSelector: '.NB-story-star' }, function($t, $p){
e.preventDefault();
var story_id = $t.parents('.story').data('story_id');
self.mark_story_as_dislike(story_id, $t);
self.mark_story_as_starred(story_id, $t);
story_prevent_bubbling = true;
});
$.targetIs(e, { tagSelector: 'a.button.like' }, function($t, $p){