Fetching all unread stories, ordered by recency.

This commit is contained in:
Samuel Clay 2013-06-16 14:09:28 -07:00
parent 3c66d7ece4
commit 3d8d1247b1
5 changed files with 83 additions and 56 deletions

View file

@ -770,24 +770,29 @@ def load_river_stories__redis(request):
start = time.time()
user = get_user(request)
feed_ids = [int(feed_id) for feed_id in request.REQUEST.getlist('feeds') if feed_id]
story_hashes = request.REQUEST.getlist('h')[:100]
original_feed_ids = list(feed_ids)
page = int(request.REQUEST.get('page', 1))
order = request.REQUEST.get('order', 'newest')
read_filter = request.REQUEST.get('read_filter', 'unread')
now = localtime_for_timezone(datetime.datetime.now(), user.profile.timezone)
if not feed_ids:
if not feed_ids and not story_hashes:
usersubs = UserSubscription.objects.filter(user=user, active=True).only('feed')
feed_ids = [sub.feed_id for sub in usersubs]
offset = (page-1) * limit
limit = page * limit - 1
story_hashes, unread_feed_story_hashes = UserSubscription.feed_stories(user.pk, feed_ids,
offset=offset, limit=limit,
order=order,
read_filter=read_filter)
story_date_order = "%sstory_date" % ('' if order == 'oldest' else '-')
if story_hashes:
unread_feed_story_hashes = []
read_filter = 'unread'
else:
story_hashes, unread_feed_story_hashes = UserSubscription.feed_stories(user.pk, feed_ids,
offset=offset, limit=limit,
order=order,
read_filter=read_filter)
mstories = MStory.objects(story_hash__in=story_hashes).order_by(story_date_order)
stories = Feed.format_stories(mstories)
found_feed_ids = list(set([story['story_feed_id'] for story in stories]))
@ -853,7 +858,7 @@ def load_river_stories__redis(request):
"stories, ~SN%s/%s/%s feeds, %s/%s)" %
(page, len(stories), len(mstories), len(found_feed_ids),
len(feed_ids), len(original_feed_ids), order, read_filter))
if page == 1:
if page == 1:
import random
time.sleep(random.randint(0, 6))
@ -922,7 +927,7 @@ 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'))
raise Http404
try:
usersub = UserSubscription.objects.select_related('feed').get(user=request.user, feed=feed_id)
except Feed.DoesNotExist:
@ -964,7 +969,7 @@ 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)
data = usersub.mark_story_ids_as_read(story_ids)
data = usersub.mark_story_ids_as_read(story_ids, request=request)
except UserSubscription.DoesNotExist:
return dict(code=-1, error="You are not subscribed to this feed_id: %d" % feed_id)
except Feed.DoesNotExist:
@ -973,7 +978,7 @@ def mark_feed_stories_as_read(request):
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)
data = usersub.mark_story_ids_as_read(story_ids, request=request)
except (UserSubscription.DoesNotExist, Feed.DoesNotExist):
return dict(code=-1, error="No feed exists for feed_id: %d" % feed_id)

View file

@ -112,6 +112,7 @@
NSInteger selectedIntelligence;
int visibleUnreadCount;
int savedStoriesCount;
int totalUnfetchedStoryCount;
NSMutableArray * recentlyReadStories;
NSMutableSet * recentlyReadFeeds;
NSMutableArray * readStories;
@ -200,6 +201,7 @@
@property (readwrite) int originalStoryCount;
@property (readwrite) int visibleUnreadCount;
@property (readwrite) int savedStoriesCount;
@property (readwrite) int totalUnfetchedStoryCount;
@property (readwrite) NSInteger selectedIntelligence;
@property (readwrite) NSMutableArray * recentlyReadStories;
@property (readwrite) NSMutableSet * recentlyReadFeeds;
@ -321,8 +323,8 @@
- (void)fetchAllUnreadStories;
- (void)fetchAllUnreadStories:(int)page;
- (void)storeAllUnreadStories:(ASIHTTPRequest *)request;
- (void)flushQueuedReadStories:(BOOL)forceCheck;
- (void)syncQueuedReadStories:(FMDatabase *)db withStories:(NSDictionary *)hashes;
- (void)flushQueuedReadStories:(BOOL)forceCheck withCallback:(void(^)())callback;
- (void)syncQueuedReadStories:(FMDatabase *)db withStories:(NSDictionary *)hashes withCallback:(void(^)())callback;
@end

View file

@ -114,6 +114,7 @@
@synthesize storyLocationsCount;
@synthesize visibleUnreadCount;
@synthesize savedStoriesCount;
@synthesize totalUnfetchedStoryCount;
@synthesize originalStoryCount;
@synthesize selectedIntelligence;
@synthesize activeOriginalStoryURL;
@ -244,6 +245,7 @@
- (void)viewDidLoad {
self.visibleUnreadCount = 0;
self.savedStoriesCount = 0;
self.totalUnfetchedStoryCount = 0;
[self setRecentlyReadStories:[NSMutableArray array]];
}
@ -520,7 +522,7 @@
[feedDetailViewController resetFeedDetail];
[feedDetailViewController fetchFeedDetail:1 withCallback:nil];
[self flushQueuedReadStories:NO];
[self flushQueuedReadStories:NO withCallback:nil];
}
- (void)loadTryFeedDetailView:(NSString *)feedId
@ -2114,19 +2116,39 @@
}
}
}];
[self fetchAllUnreadStories];
});
}
- (void)fetchAllUnreadStories {
- (NSArray *)unfetchedStoryHashes {
NSMutableArray *hashes = [NSMutableArray array];
[self fetchAllUnreadStories:1];
[self.database inDatabase:^(FMDatabase *db) {
if (self.totalUnfetchedStoryCount == 0) {
FMResultSet *cursor = [db executeQuery:@"SELECT COUNT(1) FROM unread_hashes u LEFT OUTER JOIN stories s ON (s.story_hash = u.story_hash) WHERE s.story_hash IS NULL"];
while ([cursor next]) {
self.totalUnfetchedStoryCount = [cursor objectForColumnIndex:0];
}
}
FMResultSet *cursor = [db executeQuery:@"SELECT u.story_hash FROM unread_hashes u LEFT OUTER JOIN stories s ON (s.story_hash = u.story_hash) WHERE s.story_hash IS NULL ORDER BY s.story_timestamp LIMIT 100"];
while ([cursor next]) {
[hashes addObject:[cursor objectForColumnName:@"story_hash"]];
}
}];
return hashes;
}
- (void)fetchAllUnreadStories:(int)page {
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/reader/river_stories?read_filter=unread&order=newest&page=%d",
NEWSBLUR_URL, page]];
- (void)fetchAllUnreadStories {
NSArray *hashes = [self unfetchedStoryHashes];
if ([hashes count] == 0) {
NSLog(@"Finished downloading unread stories. %d total", self.totalUnfetchedStoryCount);
return;
}
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/reader/river_stories?page=0&h=%@",
NEWSBLUR_URL, [hashes componentsJoinedByString:@"&h="]]];
ASIHTTPRequest *_request = [ASIHTTPRequest requestWithURL:url];
__weak ASIHTTPRequest *request = _request;
[request setResponseEncoding:NSUTF8StringEncoding];
@ -2149,14 +2171,28 @@
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
__block BOOL anySuccess = NO;
for (NSDictionary *story in [results objectForKey:@"stories"]) {
[self.database inTransaction:^(FMDatabase *db, BOOL *rollback) {
for (NSDictionary *story in [results objectForKey:@"stories"]) {
BOOL inserted = [db executeUpdate:@"INSERT into stories"
"(story_feed_id, story_hash, story_timestamp, story_json) VALUES "
"(?, ?, ?, ?)",
[story objectForKey:@"story_feed_id"],
[story objectForKey:@"story_hash"],
[story objectForKey:@"story_timestamp"],
[story JSONRepresentation]
];
if (inserted) anySuccess = YES;
}
}];
if (anySuccess) {
[self fetchAllUnreadStories];
}
}
- (void)flushQueuedReadStories:(BOOL)forceCheck {
- (void)flushQueuedReadStories:(BOOL)forceCheck withCallback:(void(^)())callback {
if (hasQueuedReadStories || forceCheck) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) {
@ -2174,14 +2210,18 @@
if ([[hashes allKeys] count]) {
hasQueuedReadStories = NO;
[self syncQueuedReadStories:db withStories:hashes];
[self syncQueuedReadStories:db withStories:hashes withCallback:callback];
} else {
if (callback) callback();
}
}];
});
} else {
if (callback) callback();
}
}
- (void)syncQueuedReadStories:(FMDatabase *)db withStories:(NSDictionary *)hashes {
- (void)syncQueuedReadStories:(FMDatabase *)db withStories:(NSDictionary *)hashes withCallback:(void(^)())callback {
NSString *urlString = [NSString stringWithFormat:@"http://%@/reader/mark_feed_stories_as_read",
NEWSBLUR_URL];
NSURL *url = [NSURL URLWithString:urlString];
@ -2197,10 +2237,12 @@
NSLog(@"Completed clearing %@ hashes", completedHashesStr);
[db executeUpdate:[NSString stringWithFormat:@"DELETE FROM queued_read_hashes WHERE story_hash in (\"%@\")", completedHashesStr]]
;
if (callback) callback();
}];
[request setFailedBlock:^{
NSLog(@"Failed mark read queued.");
hasQueuedReadStories = YES;
if (callback) callback();
}];
[request startAsynchronous];
}

View file

@ -679,10 +679,15 @@ static const CGFloat kFolderTitleHeight = 28;
[upgradeConfirm setTag:2];
}
if (!self.inPullToRefresh_) {
[self refreshFeedList];
} else {
if (self.inPullToRefresh_) {
self.inPullToRefresh_ = NO;
[self.appDelegate flushQueuedReadStories:YES withCallback:^{
[self.appDelegate fetchUnreadHashes];
}];
} else {
[self.appDelegate flushQueuedReadStories:YES withCallback:^{
[self refreshFeedList];
}];
}
// start up the first time user experience
@ -1471,7 +1476,6 @@ heightForHeaderInSection:(NSInteger)section {
[appDelegate.folderCountCache removeAllObjects];
[self.feedTitlesTable reloadData];
[self refreshHeaderCounts];
[self.appDelegate flushQueuedReadStories:YES];
[self.appDelegate fetchUnreadHashes];
}

View file

@ -16,19 +16,6 @@
landmarkName = "-resizeScrollView"
landmarkType = "5">
</FileBreakpoint>
<FileBreakpoint
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Classes/NewsBlurAppDelegate.m"
timestampString = "393041779.344441"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "715"
endingLineNumber = "715"
landmarkName = "-recalculateIntelligenceScores:"
landmarkType = "5">
</FileBreakpoint>
<FileBreakpoint
shouldBeEnabled = "No"
ignoreCount = "0"
@ -42,19 +29,6 @@
landmarkName = "-doNextUnreadStory"
landmarkType = "5">
</FileBreakpoint>
<FileBreakpoint
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "Classes/NewsBlurViewController.m"
timestampString = "393043837.427452"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "889"
endingLineNumber = "889"
landmarkName = "-tableView:didSelectRowAtIndexPath:"
landmarkType = "5">
</FileBreakpoint>
</FileBreakpoints>
<SymbolicBreakpoints>
<SymbolicBreakpoint