Merge remote-tracking branch 'upstream/master'
|
@ -187,6 +187,7 @@ class UserAgentBanMiddleware:
|
|||
|
||||
if 'profile' in request.path: return
|
||||
if 'haproxy' in request.path: return
|
||||
if getattr(settings, 'TEST_DEBUG'): return
|
||||
|
||||
if any(ua in user_agent for ua in BANNED_USER_AGENTS):
|
||||
data = {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
"pk": 1,
|
||||
"model": "reader.usersubscriptionfolders",
|
||||
"fields": {
|
||||
"folders": "[1, {\"Tech\": [4, 5, {\"Deep Tech\": [6, 7]}]}, 2, 3, 8, 9, {\"Blogs\": [8, 9]}]",
|
||||
"folders": "[{\"Tech\": [1, 4, 5, {\"Deep Tech\": [6, 7]}]}, 2, 3, 8, 9, {\"Blogs\": [8, 9]}, 1]",
|
||||
"user": 1
|
||||
}
|
||||
},
|
||||
|
|
|
@ -918,6 +918,24 @@ class UserSubscriptionFolders(models.Model):
|
|||
self.folders = json.encode(user_sub_folders)
|
||||
self.save()
|
||||
|
||||
def arranged_folders(self):
|
||||
user_sub_folders = json.decode(self.folders)
|
||||
def _arrange_folder(folder):
|
||||
folder_feeds = []
|
||||
folder_folders = []
|
||||
for item in folder:
|
||||
if isinstance(item, int):
|
||||
folder_feeds.append(item)
|
||||
elif isinstance(item, dict):
|
||||
for f_k, f_v in item.items():
|
||||
arranged_folder = _arrange_folder(f_v)
|
||||
folder_folders.append({f_k: arranged_folder})
|
||||
|
||||
arranged_folder = folder_feeds + folder_folders
|
||||
return arranged_folder
|
||||
|
||||
return _arrange_folder(user_sub_folders)
|
||||
|
||||
def delete_feed(self, feed_id, in_folder, commit_delete=True):
|
||||
def _find_feed_in_folders(old_folders, folder_name='', multiples_found=False, deleted=False):
|
||||
new_folders = []
|
||||
|
@ -944,7 +962,7 @@ class UserSubscriptionFolders(models.Model):
|
|||
|
||||
return new_folders, multiples_found, deleted
|
||||
|
||||
user_sub_folders = json.decode(self.folders)
|
||||
user_sub_folders = self.arranged_folders()
|
||||
user_sub_folders, multiples_found, deleted = _find_feed_in_folders(user_sub_folders)
|
||||
self.folders = json.encode(user_sub_folders)
|
||||
self.save()
|
||||
|
|
|
@ -6,7 +6,9 @@ from django.conf import settings
|
|||
from mongoengine.connection import connect, disconnect
|
||||
|
||||
class ReaderTest(TestCase):
|
||||
fixtures = ['subscriptions.json', 'stories.json', '../../rss_feeds/fixtures/gawker1.json']
|
||||
fixtures = ['../../rss_feeds/fixtures/rss_feeds.json',
|
||||
'subscriptions.json', 'stories.json',
|
||||
'../../rss_feeds/fixtures/gawker1.json']
|
||||
|
||||
|
||||
def setUp(self):
|
||||
|
@ -23,16 +25,16 @@ class ReaderTest(TestCase):
|
|||
response = self.client.get(reverse('load-feeds'))
|
||||
content = json.decode(response.content)
|
||||
|
||||
self.assertEquals(len(content['feeds']), 1)
|
||||
self.assertEquals(len(content['feeds']), 10)
|
||||
self.assertEquals(content['feeds']['1']['feed_title'], 'Gawker')
|
||||
self.assertEquals(content['folders'], [1, {'Tech': [4, 5, {'Deep Tech': [6, 7]}]}, 2, 3, 8, 9, {'Blogs': [8, 9]}])
|
||||
self.assertEquals(content['folders'], [{'Tech': [1, 4, 5, {'Deep Tech': [6, 7]}]}, 2, 3, 8, 9, {'Blogs': [8, 9]}, 1])
|
||||
|
||||
def test_delete_feed(self):
|
||||
self.client.login(username='conesus', password='test')
|
||||
|
||||
response = self.client.get(reverse('load-feeds'))
|
||||
feeds = json.decode(response.content)
|
||||
self.assertEquals(feeds['folders'], [1, {'Tech': [4, 5, {'Deep Tech': [6, 7]}]}, 2, 3, 8, 9, {'Blogs': [8, 9]}])
|
||||
self.assertEquals(feeds['folders'], [{'Tech': [1, 4, 5, {'Deep Tech': [6, 7]}]}, 2, 3, 8, 9, {'Blogs': [8, 9]}, 1])
|
||||
|
||||
# Delete feed
|
||||
response = self.client.post(reverse('delete-feed'), {'feed_id': 1, 'in_folder': ''})
|
||||
|
@ -41,7 +43,7 @@ class ReaderTest(TestCase):
|
|||
|
||||
response = self.client.get(reverse('load-feeds'))
|
||||
feeds = json.decode(response.content)
|
||||
self.assertEquals(feeds['folders'], [{'Tech': [4, 5, {'Deep Tech': [6, 7]}]}, 2, 3, 8, 9, {'Blogs': [8, 9]}])
|
||||
self.assertEquals(feeds['folders'], [2, 3, 8, 9, {'Tech': [1, 4, 5, {'Deep Tech': [6, 7]}]}, {'Blogs': [8, 9]}])
|
||||
|
||||
# Delete feed
|
||||
response = self.client.post(reverse('delete-feed'), {'feed_id': 9, 'in_folder': 'Blogs'})
|
||||
|
@ -50,7 +52,7 @@ class ReaderTest(TestCase):
|
|||
|
||||
response = self.client.get(reverse('load-feeds'))
|
||||
feeds = json.decode(response.content)
|
||||
self.assertEquals(feeds['folders'], [{'Tech': [4, 5, {'Deep Tech': [6, 7]}]}, 2, 3, 8, 9, {'Blogs': [8]}])
|
||||
self.assertEquals(feeds['folders'], [2, 3, 8, 9, {'Tech': [1, 4, 5, {'Deep Tech': [6, 7]}]}, {'Blogs': [8]}])
|
||||
|
||||
# Delete feed
|
||||
response = self.client.post(reverse('delete-feed'), {'feed_id': 5, 'in_folder': 'Tech'})
|
||||
|
@ -59,7 +61,7 @@ class ReaderTest(TestCase):
|
|||
|
||||
response = self.client.get(reverse('load-feeds'))
|
||||
feeds = json.decode(response.content)
|
||||
self.assertEquals(feeds['folders'], [{'Tech': [4, {'Deep Tech': [6, 7]}]}, 2, 3, 8, 9, {'Blogs': [8]}])
|
||||
self.assertEquals(feeds['folders'], [2, 3, 8, 9, {'Tech': [1, 4, {'Deep Tech': [6, 7]}]}, {'Blogs': [8]}])
|
||||
|
||||
# Delete feed
|
||||
response = self.client.post(reverse('delete-feed'), {'feed_id': 4, 'in_folder': 'Tech'})
|
||||
|
@ -68,7 +70,7 @@ class ReaderTest(TestCase):
|
|||
|
||||
response = self.client.get(reverse('load-feeds'))
|
||||
feeds = json.decode(response.content)
|
||||
self.assertEquals(feeds['folders'], [{'Tech': [{'Deep Tech': [6, 7]}]}, 2, 3, 8, 9, {'Blogs': [8]}])
|
||||
self.assertEquals(feeds['folders'], [2, 3, 8, 9, {'Tech': [1, {'Deep Tech': [6, 7]}]}, {'Blogs': [8]}])
|
||||
|
||||
# Delete feed
|
||||
response = self.client.post(reverse('delete-feed'), {'feed_id': 8, 'in_folder': ''})
|
||||
|
@ -77,7 +79,23 @@ class ReaderTest(TestCase):
|
|||
|
||||
response = self.client.get(reverse('load-feeds'))
|
||||
feeds = json.decode(response.content)
|
||||
self.assertEquals(feeds['folders'], [{'Tech': [{'Deep Tech': [6, 7]}]}, 2, 3, 9, {'Blogs': [8]}])
|
||||
self.assertEquals(feeds['folders'], [2, 3, 9, {'Tech': [1, {'Deep Tech': [6, 7]}]}, {'Blogs': [8]}])
|
||||
|
||||
def test_delete_feed__multiple_folders(self):
|
||||
self.client.login(username='conesus', password='test')
|
||||
|
||||
response = self.client.get(reverse('load-feeds'))
|
||||
feeds = json.decode(response.content)
|
||||
self.assertEquals(feeds['folders'], [{'Tech': [1, 4, 5, {'Deep Tech': [6, 7]}]}, 2, 3, 8, 9, {'Blogs': [8, 9]}, 1])
|
||||
|
||||
# Delete feed
|
||||
response = self.client.post(reverse('delete-feed'), {'feed_id': 1})
|
||||
response = json.decode(response.content)
|
||||
self.assertEquals(response['code'], 1)
|
||||
|
||||
response = self.client.get(reverse('load-feeds'))
|
||||
feeds = json.decode(response.content)
|
||||
self.assertEquals(feeds['folders'], [2, 3, 8, 9, {'Tech': [1, 4, 5, {'Deep Tech': [6, 7]}]}, {'Blogs': [8, 9]}])
|
||||
|
||||
def test_load_single_feed(self):
|
||||
# from django.conf import settings
|
||||
|
|
|
@ -607,8 +607,9 @@ def load_single_feed(request, feed_id):
|
|||
if not include_story_content:
|
||||
del story['story_content']
|
||||
story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date)
|
||||
story['long_parsed_date'] = format_story_link_date__long(story_date, now)
|
||||
nowtz = localtime_for_timezone(now, user.profile.timezone)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date, nowtz)
|
||||
story['long_parsed_date'] = format_story_link_date__long(story_date, nowtz)
|
||||
if usersub:
|
||||
story['read_status'] = 1
|
||||
if (read_filter == 'all' or query) and usersub:
|
||||
|
@ -782,12 +783,13 @@ def load_starred_stories(request):
|
|||
comments=story.comments))
|
||||
for story in shared_stories])
|
||||
|
||||
nowtz = localtime_for_timezone(now, user.profile.timezone)
|
||||
for story in stories:
|
||||
story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date)
|
||||
story['long_parsed_date'] = format_story_link_date__long(story_date, now)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date, nowtz)
|
||||
story['long_parsed_date'] = format_story_link_date__long(story_date, nowtz)
|
||||
starred_date = localtime_for_timezone(story['starred_date'], user.profile.timezone)
|
||||
story['starred_date'] = format_story_link_date__long(starred_date, now)
|
||||
story['starred_date'] = format_story_link_date__long(starred_date, nowtz)
|
||||
story['read_status'] = 1
|
||||
story['starred'] = True
|
||||
story['intelligence'] = {
|
||||
|
@ -939,6 +941,7 @@ def load_river_stories__redis(request):
|
|||
|
||||
|
||||
# Just need to format stories
|
||||
nowtz = localtime_for_timezone(now, user.profile.timezone)
|
||||
for story in stories:
|
||||
story['read_status'] = 0
|
||||
if read_filter == 'all':
|
||||
|
@ -946,8 +949,8 @@ def load_river_stories__redis(request):
|
|||
story['story_hash'] not in unread_feed_story_hashes):
|
||||
story['read_status'] = 1
|
||||
story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date)
|
||||
story['long_parsed_date'] = format_story_link_date__long(story_date, now)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date, nowtz)
|
||||
story['long_parsed_date'] = format_story_link_date__long(story_date, nowtz)
|
||||
if story['story_hash'] in starred_stories:
|
||||
story['starred'] = True
|
||||
starred_date = localtime_for_timezone(starred_stories[story['story_hash']],
|
||||
|
@ -1399,7 +1402,7 @@ def add_folder(request):
|
|||
def delete_feed(request):
|
||||
feed_id = int(request.POST['feed_id'])
|
||||
in_folder = request.POST.get('in_folder', None)
|
||||
if in_folder == ' ':
|
||||
if not in_folder or in_folder == ' ':
|
||||
in_folder = ""
|
||||
|
||||
user_sub_folders = get_object_or_404(UserSubscriptionFolders, user=request.user)
|
||||
|
|
|
@ -136,5 +136,302 @@
|
|||
"email": "samuel@newsblur.com",
|
||||
"date_joined": "2009-01-04 17:32:58"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"pk": 2,
|
||||
"model": "rss_feeds.feed",
|
||||
"fields": {
|
||||
"premium_subscribers": -1,
|
||||
"creation": "2011-08-27",
|
||||
"exception_code": 0,
|
||||
"last_load_time": 0,
|
||||
"active_subscribers": 1,
|
||||
"feed_address": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker2.xml",
|
||||
"feed_link": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker2.html",
|
||||
"hash_address_and_link": "2",
|
||||
"feed_link_locked": true,
|
||||
"last_update": "2011-08-27 02:45:21",
|
||||
"etag": null,
|
||||
"average_stories_per_month": 0,
|
||||
"feed_title": "Gawker",
|
||||
"last_modified": null,
|
||||
"next_scheduled_update": "2011-08-28 14:33:50",
|
||||
"favicon_color": null,
|
||||
"stories_last_month": 0,
|
||||
"active": true,
|
||||
"favicon_not_found": false,
|
||||
"has_page_exception": false,
|
||||
"fetched_once": false,
|
||||
"days_to_trim": 90,
|
||||
"num_subscribers": 1,
|
||||
"last_story_date": "2011-08-28 00:03:50",
|
||||
"min_to_decay": 720,
|
||||
"has_feed_exception": false
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"pk": 3,
|
||||
"model": "rss_feeds.feed",
|
||||
"fields": {
|
||||
"premium_subscribers": -1,
|
||||
"creation": "2011-08-27",
|
||||
"exception_code": 0,
|
||||
"last_load_time": 0,
|
||||
"active_subscribers": 1,
|
||||
"feed_address": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker3.xml",
|
||||
"feed_link": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker3.html",
|
||||
"hash_address_and_link": "3",
|
||||
"feed_link_locked": true,
|
||||
"last_update": "2011-08-27 02:45:21",
|
||||
"etag": null,
|
||||
"average_stories_per_month": 0,
|
||||
"feed_title": "Gawker",
|
||||
"last_modified": null,
|
||||
"next_scheduled_update": "2011-08-28 14:33:50",
|
||||
"favicon_color": null,
|
||||
"stories_last_month": 0,
|
||||
"active": true,
|
||||
"favicon_not_found": false,
|
||||
"has_page_exception": false,
|
||||
"fetched_once": false,
|
||||
"days_to_trim": 90,
|
||||
"num_subscribers": 1,
|
||||
"last_story_date": "2011-08-28 00:03:50",
|
||||
"min_to_decay": 720,
|
||||
"has_feed_exception": false
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"pk": 4,
|
||||
"model": "rss_feeds.feed",
|
||||
"fields": {
|
||||
"premium_subscribers": -1,
|
||||
"creation": "2011-08-27",
|
||||
"exception_code": 0,
|
||||
"last_load_time": 0,
|
||||
"active_subscribers": 1,
|
||||
"feed_address": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker4.xml",
|
||||
"feed_link": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker4.html",
|
||||
"hash_address_and_link": "4",
|
||||
"feed_link_locked": true,
|
||||
"last_update": "2011-08-27 02:45:21",
|
||||
"etag": null,
|
||||
"average_stories_per_month": 0,
|
||||
"feed_title": "Gawker",
|
||||
"last_modified": null,
|
||||
"next_scheduled_update": "2011-08-28 14:33:50",
|
||||
"favicon_color": null,
|
||||
"stories_last_month": 0,
|
||||
"active": true,
|
||||
"favicon_not_found": false,
|
||||
"has_page_exception": false,
|
||||
"fetched_once": false,
|
||||
"days_to_trim": 90,
|
||||
"num_subscribers": 1,
|
||||
"last_story_date": "2011-08-28 00:03:50",
|
||||
"min_to_decay": 720,
|
||||
"has_feed_exception": false
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"pk": 5,
|
||||
"model": "rss_feeds.feed",
|
||||
"fields": {
|
||||
"premium_subscribers": -1,
|
||||
"creation": "2011-08-27",
|
||||
"exception_code": 0,
|
||||
"last_load_time": 0,
|
||||
"active_subscribers": 1,
|
||||
"feed_address": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker5.xml",
|
||||
"feed_link": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker5.html",
|
||||
"hash_address_and_link": "5",
|
||||
"feed_link_locked": true,
|
||||
"last_update": "2011-08-27 02:45:21",
|
||||
"etag": null,
|
||||
"average_stories_per_month": 0,
|
||||
"feed_title": "Gawker",
|
||||
"last_modified": null,
|
||||
"next_scheduled_update": "2011-08-28 14:33:50",
|
||||
"favicon_color": null,
|
||||
"stories_last_month": 0,
|
||||
"active": true,
|
||||
"favicon_not_found": false,
|
||||
"has_page_exception": false,
|
||||
"fetched_once": false,
|
||||
"days_to_trim": 90,
|
||||
"num_subscribers": 1,
|
||||
"last_story_date": "2011-08-28 00:03:50",
|
||||
"min_to_decay": 720,
|
||||
"has_feed_exception": false
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"pk": 6,
|
||||
"model": "rss_feeds.feed",
|
||||
"fields": {
|
||||
"premium_subscribers": -1,
|
||||
"creation": "2011-08-27",
|
||||
"exception_code": 0,
|
||||
"last_load_time": 0,
|
||||
"active_subscribers": 1,
|
||||
"feed_address": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker6.xml",
|
||||
"feed_link": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker6.html",
|
||||
"hash_address_and_link": "6",
|
||||
"feed_link_locked": true,
|
||||
"last_update": "2011-08-27 02:45:21",
|
||||
"etag": null,
|
||||
"average_stories_per_month": 0,
|
||||
"feed_title": "Gawker",
|
||||
"last_modified": null,
|
||||
"next_scheduled_update": "2011-08-28 14:33:50",
|
||||
"favicon_color": null,
|
||||
"stories_last_month": 0,
|
||||
"active": true,
|
||||
"favicon_not_found": false,
|
||||
"has_page_exception": false,
|
||||
"fetched_once": false,
|
||||
"days_to_trim": 90,
|
||||
"num_subscribers": 1,
|
||||
"last_story_date": "2011-08-28 00:03:50",
|
||||
"min_to_decay": 720,
|
||||
"has_feed_exception": false
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"pk": 7,
|
||||
"model": "rss_feeds.feed",
|
||||
"fields": {
|
||||
"premium_subscribers": -1,
|
||||
"creation": "2011-08-27",
|
||||
"exception_code": 0,
|
||||
"last_load_time": 0,
|
||||
"active_subscribers": 1,
|
||||
"feed_address": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker7.xml",
|
||||
"feed_link": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker7.html",
|
||||
"hash_address_and_link": "7",
|
||||
"feed_link_locked": true,
|
||||
"last_update": "2011-08-27 02:45:21",
|
||||
"etag": null,
|
||||
"average_stories_per_month": 0,
|
||||
"feed_title": "Gawker",
|
||||
"last_modified": null,
|
||||
"next_scheduled_update": "2011-08-28 14:33:50",
|
||||
"favicon_color": null,
|
||||
"stories_last_month": 0,
|
||||
"active": true,
|
||||
"favicon_not_found": false,
|
||||
"has_page_exception": false,
|
||||
"fetched_once": false,
|
||||
"days_to_trim": 90,
|
||||
"num_subscribers": 1,
|
||||
"last_story_date": "2011-08-28 00:03:50",
|
||||
"min_to_decay": 720,
|
||||
"has_feed_exception": false
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"pk": 8,
|
||||
"model": "rss_feeds.feed",
|
||||
"fields": {
|
||||
"premium_subscribers": -1,
|
||||
"creation": "2011-08-27",
|
||||
"exception_code": 0,
|
||||
"last_load_time": 0,
|
||||
"active_subscribers": 1,
|
||||
"feed_address": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker8.xml",
|
||||
"feed_link": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker8.html",
|
||||
"hash_address_and_link": "8",
|
||||
"feed_link_locked": true,
|
||||
"last_update": "2011-08-27 02:45:21",
|
||||
"etag": null,
|
||||
"average_stories_per_month": 0,
|
||||
"feed_title": "Gawker",
|
||||
"last_modified": null,
|
||||
"next_scheduled_update": "2011-08-28 14:33:50",
|
||||
"favicon_color": null,
|
||||
"stories_last_month": 0,
|
||||
"active": true,
|
||||
"favicon_not_found": false,
|
||||
"has_page_exception": false,
|
||||
"fetched_once": false,
|
||||
"days_to_trim": 90,
|
||||
"num_subscribers": 1,
|
||||
"last_story_date": "2011-08-28 00:03:50",
|
||||
"min_to_decay": 720,
|
||||
"has_feed_exception": false
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"pk": 9,
|
||||
"model": "rss_feeds.feed",
|
||||
"fields": {
|
||||
"premium_subscribers": -1,
|
||||
"creation": "2011-08-27",
|
||||
"exception_code": 0,
|
||||
"last_load_time": 0,
|
||||
"active_subscribers": 1,
|
||||
"feed_address": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker9.xml",
|
||||
"feed_link": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker9.html",
|
||||
"hash_address_and_link": "9",
|
||||
"feed_link_locked": true,
|
||||
"last_update": "2011-08-27 02:45:21",
|
||||
"etag": null,
|
||||
"average_stories_per_month": 0,
|
||||
"feed_title": "Gawker",
|
||||
"last_modified": null,
|
||||
"next_scheduled_update": "2011-08-28 14:33:50",
|
||||
"favicon_color": null,
|
||||
"stories_last_month": 0,
|
||||
"active": true,
|
||||
"favicon_not_found": false,
|
||||
"has_page_exception": false,
|
||||
"fetched_once": false,
|
||||
"days_to_trim": 90,
|
||||
"num_subscribers": 1,
|
||||
"last_story_date": "2011-08-28 00:03:50",
|
||||
"min_to_decay": 720,
|
||||
"has_feed_exception": false
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"pk": 56,
|
||||
"model": "rss_feeds.feed",
|
||||
"fields": {
|
||||
"premium_subscribers": -1,
|
||||
"creation": "2011-08-27",
|
||||
"exception_code": 0,
|
||||
"last_load_time": 0,
|
||||
"active_subscribers": 1,
|
||||
"feed_address": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker56.xml",
|
||||
"feed_link": "%(NEWSBLUR_DIR)s/apps/rss_feeds/fixtures/gawker56.html",
|
||||
"hash_address_and_link": "56",
|
||||
"feed_link_locked": true,
|
||||
"last_update": "2011-08-27 02:45:21",
|
||||
"etag": null,
|
||||
"average_stories_per_month": 0,
|
||||
"feed_title": "Gawker",
|
||||
"last_modified": null,
|
||||
"next_scheduled_update": "2011-08-28 14:33:50",
|
||||
"favicon_color": null,
|
||||
"stories_last_month": 0,
|
||||
"active": true,
|
||||
"favicon_not_found": false,
|
||||
"has_page_exception": false,
|
||||
"fetched_once": false,
|
||||
"days_to_trim": 90,
|
||||
"num_subscribers": 1,
|
||||
"last_story_date": "2011-08-28 00:03:50",
|
||||
"min_to_decay": 720,
|
||||
"has_feed_exception": false
|
||||
}
|
||||
}
|
||||
]
|
|
@ -912,6 +912,7 @@ class Feed(models.Model):
|
|||
story_content = strip_comments(story_content)
|
||||
story_tags = self.get_tags(story)
|
||||
story_link = self.get_permalink(story)
|
||||
replace_story_date = False
|
||||
|
||||
try:
|
||||
existing_story, story_has_changed = _1(story, story_content, existing_stories)
|
||||
|
@ -937,11 +938,18 @@ class Feed(models.Model):
|
|||
try:
|
||||
s.save()
|
||||
ret_values['new'] += 1
|
||||
except (IntegrityError, OperationError), e:
|
||||
except (IntegrityError), e:
|
||||
ret_values['error'] += 1
|
||||
if settings.DEBUG:
|
||||
logging.info(' ---> [%-30s] ~SN~FRIntegrityError on new story: %s - %s' % (self.feed_title[:30], story.get('guid'), e))
|
||||
elif existing_story and story_has_changed:
|
||||
except OperationError, e:
|
||||
existing_story, _ = MStory.find_story(self.pk,
|
||||
story.get('guid'),
|
||||
original_only=True)
|
||||
story_has_changed = True
|
||||
replace_story_date = True
|
||||
|
||||
if existing_story and story_has_changed:
|
||||
# update story
|
||||
original_content = None
|
||||
try:
|
||||
|
@ -993,7 +1001,8 @@ class Feed(models.Model):
|
|||
existing_story.story_tags = story_tags
|
||||
# Do not allow publishers to change the story date once a story is published.
|
||||
# Leads to incorrect unread story counts.
|
||||
# existing_story.story_date = story.get('published') # No, don't
|
||||
if replace_story_date:
|
||||
existing_story.story_date = story.get('published') # Really shouldn't do this.
|
||||
existing_story.extract_image_urls()
|
||||
|
||||
try:
|
||||
|
|
|
@ -3001,14 +3001,17 @@ class MActivity(mongo.Document):
|
|||
|
||||
@classmethod
|
||||
def remove_shared_story(cls, user_id, story_feed_id, story_id):
|
||||
try:
|
||||
a = cls.objects.get(user_id=user_id,
|
||||
params = dict(user_id=user_id,
|
||||
category='sharedstory',
|
||||
feed_id="social:%s" % user_id,
|
||||
story_feed_id=story_feed_id,
|
||||
content_id=story_id)
|
||||
try:
|
||||
a = cls.objects.get(**params)
|
||||
except cls.DoesNotExist:
|
||||
return
|
||||
except cls.MultipleObjectsReturned:
|
||||
a = cls.objects.filter(**params)
|
||||
|
||||
a.delete()
|
||||
|
||||
|
|
|
@ -119,12 +119,13 @@ def load_social_stories(request, user_id, username=None):
|
|||
comments=story.comments))
|
||||
for story in shared_stories])
|
||||
|
||||
nowtz = localtime_for_timezone(now, user.profile.timezone)
|
||||
for story in stories:
|
||||
story['social_user_id'] = social_user_id
|
||||
# story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
|
||||
shared_date = localtime_for_timezone(story['shared_date'], user.profile.timezone)
|
||||
story['short_parsed_date'] = format_story_link_date__short(shared_date)
|
||||
story['long_parsed_date'] = format_story_link_date__long(shared_date)
|
||||
story['short_parsed_date'] = format_story_link_date__short(shared_date, nowtz)
|
||||
story['long_parsed_date'] = format_story_link_date__long(shared_date, nowtz)
|
||||
|
||||
story['read_status'] = 1
|
||||
if (read_filter == 'all' or query) and socialsub:
|
||||
|
@ -270,13 +271,14 @@ def load_river_blurblog(request):
|
|||
classifier_tags = []
|
||||
|
||||
# Just need to format stories
|
||||
nowtz = localtime_for_timezone(now, user.profile.timezone)
|
||||
for story in stories:
|
||||
story['read_status'] = 0
|
||||
if story['story_hash'] not in unread_feed_story_hashes:
|
||||
story['read_status'] = 1
|
||||
story_date = localtime_for_timezone(story['story_date'], user.profile.timezone)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date)
|
||||
story['long_parsed_date'] = format_story_link_date__long(story_date, now)
|
||||
story['short_parsed_date'] = format_story_link_date__short(story_date, nowtz)
|
||||
story['long_parsed_date'] = format_story_link_date__long(story_date, nowtz)
|
||||
if story['story_hash'] in starred_stories:
|
||||
story['starred'] = True
|
||||
starred_date = localtime_for_timezone(starred_stories[story['story_hash']], user.profile.timezone)
|
||||
|
@ -522,6 +524,8 @@ def mark_story_as_shared(request):
|
|||
relative_user_id = request.POST.get('relative_user_id') or request.user.pk
|
||||
post_to_services = request.POST.getlist('post_to_services')
|
||||
format = request.REQUEST.get('format', 'json')
|
||||
now = datetime.datetime.now()
|
||||
nowtz = localtime_for_timezone(now, request.user.profile.timezone)
|
||||
|
||||
MSocialProfile.get_user(request.user.pk)
|
||||
|
||||
|
@ -576,8 +580,8 @@ def mark_story_as_shared(request):
|
|||
story['shared_by_user'] = True
|
||||
story['shared'] = True
|
||||
shared_date = localtime_for_timezone(shared_story['shared_date'], request.user.profile.timezone)
|
||||
story['short_parsed_date'] = format_story_link_date__short(shared_date)
|
||||
story['long_parsed_date'] = format_story_link_date__long(shared_date)
|
||||
story['short_parsed_date'] = format_story_link_date__short(shared_date, nowtz)
|
||||
story['long_parsed_date'] = format_story_link_date__long(shared_date, nowtz)
|
||||
|
||||
if post_to_services:
|
||||
for service in post_to_services:
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.newsblur"
|
||||
android:versionCode="43"
|
||||
android:versionName="2.5.0" >
|
||||
android:versionCode="44"
|
||||
android:versionName="3.0.0" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="8"
|
||||
|
|
|
@ -10,16 +10,23 @@
|
|||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android 4.2.2" jdkType="Android SDK" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="android-support-v4" level="project" />
|
||||
<orderEntry type="library" name="actionbarsherlock" level="project" />
|
||||
<orderEntry type="library" name="gson-2.2.3" level="project" />
|
||||
<orderEntry type="library" name="classes" level="project" />
|
||||
<orderEntry type="module" module-name="ActionBarSherlock" />
|
||||
<orderEntry type="library" name="android-support-v4" level="project" />
|
||||
<orderEntry type="module-library">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/libs/ActionBarSherlock/bin/actionbarsherlock.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
|
|
@ -11,12 +11,11 @@
|
|||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android 4.2.2" jdkType="Android SDK" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="android-support-v4" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
|
|
@ -9,4 +9,4 @@
|
|||
|
||||
android.library=true
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-14
|
||||
|
|
|
@ -11,5 +11,5 @@
|
|||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-17
|
||||
target=android-14
|
||||
android.library.reference.1=libs/ActionBarSherlock
|
||||
|
|
BIN
clients/android/NewsBlur/res/drawable-hdpi/clock.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.6 KiB |
BIN
clients/android/NewsBlur/res/drawable-hdpi/share_icon.png
Normal file
After Width: | Height: | Size: 820 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 605 B |
Before Width: | Height: | Size: 605 B |
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/feed_background_selected_start"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item
|
||||
android:top="0.5dp"
|
||||
android:bottom="0.5dp">
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/feed_background_selected_end"/>
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="90"
|
||||
android:type="linear"
|
||||
android:startColor="@color/folder_background_start"
|
||||
android:endColor="@color/folder_background_end"/>
|
||||
</shape>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="90"
|
||||
android:type="linear"
|
||||
android:startColor="@color/folder_background_selected_start"
|
||||
android:endColor="@color/folder_background_selected_end"/>
|
||||
</shape>
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 20 KiB |
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:state_pressed="true" android:drawable="@drawable/gradient_activation_highlight" />
|
||||
<item android:state_pressed="true" android:drawable="@drawable/feed_background_highlight" />
|
||||
<item android:drawable="@drawable/feed_background_default" />
|
||||
</selector>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:state_pressed="true" android:drawable="@drawable/gradient_activation_highlight" />
|
||||
<item android:drawable="@drawable/gradient_background_default" />
|
||||
<item android:state_pressed="true" android:drawable="@drawable/folder_background_highlight" />
|
||||
<item android:drawable="@drawable/folder_background_default" />
|
||||
</selector>
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@drawable/story_background_highlight"/>
|
||||
<item android:drawable="@drawable/story_background_default"/>
|
||||
</selector>
|
Before Width: | Height: | Size: 517 B After Width: | Height: | Size: 517 B |
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/story_background"/>
|
||||
</shape>
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/story_background_start"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item
|
||||
android:top="0.5dp"
|
||||
android:bottom="0.5dp">
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/story_background_end"/>
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
|
@ -19,4 +19,13 @@
|
|||
android:defaultValue="@string/default_read_filter_value" />
|
||||
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:title="@string/settings_social">
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="true"
|
||||
android:key="show_public_comments"
|
||||
android:title="@string/settings_show_public_comments" >
|
||||
</CheckBoxPreference>
|
||||
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
|
@ -105,6 +105,18 @@
|
|||
android:textColor="@color/darkgray"
|
||||
android:textSize="14dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/comment_location"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/comment_text"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_toRightOf="@id/comment_user_image"
|
||||
android:textColor="@color/lightgray"
|
||||
android:textSize="12dp"
|
||||
/>
|
||||
|
||||
<com.newsblur.view.FlowLayout
|
||||
xmlns:newsblur="http://schemas.android.com/apk/res/com.newsblur"
|
||||
android:id="@+id/comment_favourite_avatars"
|
||||
|
@ -121,6 +133,7 @@
|
|||
|
||||
<LinearLayout
|
||||
android:id="@+id/comment_replies_container"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
|
@ -129,6 +142,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:background="#A6A6A6" />
|
||||
android:background="#F0F0F0" />
|
||||
|
||||
</LinearLayout>
|
|
@ -5,7 +5,8 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="15dp" >
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginBottom="15dp" >
|
||||
|
||||
<Button
|
||||
android:id="@+id/share_story_button"
|
||||
|
@ -20,7 +21,7 @@
|
|||
android:paddingBottom="6dp"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingRight="12dp"
|
||||
android:drawableLeft="@drawable/share_half"
|
||||
android:drawableLeft="@drawable/share_icon"
|
||||
android:text="@string/share_this" />
|
||||
|
||||
<Button
|
||||
|
@ -36,7 +37,7 @@
|
|||
android:paddingBottom="6dp"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingRight="12dp"
|
||||
android:drawableLeft="@drawable/clock_half"
|
||||
android:drawableLeft="@drawable/clock"
|
||||
android:text="@string/save_this" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -45,50 +46,102 @@
|
|||
android:id="@+id/reading_shared_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginBottom="50dp" >
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/reading_friend_comment_container"
|
||||
android:id="@+id/reading_friend_comment_header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:id="@+id/reading_friend_header_top_border"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:background="@color/lightgray"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingRight="12dp"
|
||||
android:textColor="@color/darkgray"
|
||||
android:id="@+id/reading_friend_comment_total"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:textStyle="bold"
|
||||
android:paddingBottom="3dp" />
|
||||
android:textSize="10sp"
|
||||
android:background="@drawable/gradient_background_default"
|
||||
/>
|
||||
|
||||
<View
|
||||
android:id="@+id/reading_friend_header_bottom_border"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_below="@id/reading_friend_comment_total"
|
||||
android:background="@color/lightgray"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/comment_divider"
|
||||
<LinearLayout
|
||||
android:id="@+id/reading_friend_comment_container"
|
||||
android:layout_below="@id/reading_friend_comment_header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="3dp"
|
||||
android:layout_below="@id/reading_friend_comment_container"
|
||||
android:background="@drawable/divider_light" />
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/reading_public_comment_header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/comment_divider"
|
||||
android:visibility="gone"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:id="@+id/reading_public_header_top_border"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:background="@color/lightgray"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/darkgray"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:textStyle="bold"
|
||||
android:textSize="10sp"
|
||||
android:background="@drawable/gradient_background_default"
|
||||
android:id="@+id/reading_public_comment_total" />
|
||||
|
||||
<View
|
||||
android:id="@+id/reading_public_header_bottom_border"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_below="@id/reading_public_comment_total"
|
||||
android:background="@color/lightgray"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/reading_public_comment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/comment_divider"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:layout_below="@id/reading_public_comment_header"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/darkgray"
|
||||
android:paddingTop="3dp"
|
||||
android:textStyle="bold"
|
||||
android:id="@+id/reading_public_comment_total"
|
||||
android:paddingBottom="3dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/item_background"
|
||||
android:background="@drawable/selector_story_background"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<RelativeLayout
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/selector_feed_background"
|
||||
android:background="@drawable/selector_story_background"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<RelativeLayout
|
||||
|
@ -20,7 +20,6 @@
|
|||
android:layout_height="match_parent"
|
||||
android:layout_toRightOf="@id/row_item_favicon_borderbar_1" />
|
||||
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/row_item_title_container"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/selector_feed_background"
|
||||
android:background="@drawable/selector_story_background"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<RelativeLayout
|
||||
|
|
|
@ -8,14 +8,19 @@
|
|||
|
||||
<color name="folder_background_end">#E9EBE4</color>
|
||||
<color name="folder_background_start">#DDE0D7</color>
|
||||
<color name="folder_background_selected_end">#fdfcca</color>
|
||||
<color name="folder_background_selected_start">#fbec8c</color>
|
||||
<color name="folder_background_selected_end">#D9DBD4</color>
|
||||
<color name="folder_background_selected_start">#CDD0C7</color>
|
||||
<color name="folder_text">#4C4C4C</color>
|
||||
<color name="folder_border_top">#FDFDFD</color>
|
||||
<color name="folder_border_bottom">#B7BBAA</color>
|
||||
<color name="feed_background">#F7F8F5</color>
|
||||
<color name="feed_background_end">#303030</color>
|
||||
<color name="feed_background_start">#505050</color>
|
||||
<color name="feed_background_selected_end">#FFFFD2</color>
|
||||
<color name="feed_background_selected_start">#E3D0AE</color>
|
||||
<color name="story_background">#F7F8F5</color>
|
||||
<color name="story_background_end">#FFFDEF</color>
|
||||
<color name="story_background_start">#DFDDCF</color>
|
||||
|
||||
<color name="story_title_unread">#333333</color>
|
||||
<color name="story_title_read">#808080</color>
|
||||
|
|
|
@ -190,4 +190,6 @@
|
|||
<item>Mark entire folder read</item>
|
||||
<item>Cancel</item>
|
||||
</string-array>
|
||||
<string name="settings_social">Social</string>
|
||||
<string name="settings_show_public_comments">Show Public Comments</string>
|
||||
</resources>
|
||||
|
|
|
@ -11,7 +11,7 @@ public class BlurDatabase extends SQLiteOpenHelper {
|
|||
private final String TEXT = " text";
|
||||
private final String INTEGER = " integer";
|
||||
public final static String DB_NAME = "blur.db";
|
||||
private final static int VERSION = 1;
|
||||
private final static int VERSION = 2;
|
||||
|
||||
public BlurDatabase(Context context) {
|
||||
super(context, DB_NAME, null, VERSION);
|
||||
|
@ -44,7 +44,8 @@ public class BlurDatabase extends SQLiteOpenHelper {
|
|||
private final String USER_SQL = "CREATE TABLE " + DatabaseConstants.USER_TABLE + " (" +
|
||||
DatabaseConstants.USER_PHOTO_URL + TEXT + ", " +
|
||||
DatabaseConstants.USER_USERID + INTEGER + " PRIMARY KEY, " +
|
||||
DatabaseConstants.USER_USERNAME + TEXT + ")";
|
||||
DatabaseConstants.USER_USERNAME + TEXT + ", " +
|
||||
DatabaseConstants.USER_LOCATION + TEXT + ")";
|
||||
|
||||
private final String SOCIAL_FEED_SQL = "CREATE TABLE " + DatabaseConstants.SOCIALFEED_TABLE + " (" +
|
||||
DatabaseConstants.SOCIAL_FEED_ID + INTEGER + " PRIMARY KEY, " +
|
||||
|
|
|
@ -67,6 +67,7 @@ public class DatabaseConstants {
|
|||
public static final String USER_TABLE = "user_table";
|
||||
public static final String USER_USERID = BaseColumns._ID;
|
||||
public static final String USER_USERNAME = "username";
|
||||
public static final String USER_LOCATION = "location";
|
||||
public static final String USER_PHOTO_URL = "photo_url";
|
||||
|
||||
public static final String STORY_TABLE = "stories";
|
||||
|
|
|
@ -17,6 +17,7 @@ public class UserProfile {
|
|||
public String userId;
|
||||
|
||||
public String username;
|
||||
public String location;
|
||||
|
||||
public static UserProfile fromCursor(final Cursor c) {
|
||||
if (c.isBeforeFirst()) {
|
||||
|
@ -27,6 +28,7 @@ public class UserProfile {
|
|||
profile.userId = c.getString(c.getColumnIndex(DatabaseConstants.USER_USERID));
|
||||
profile.photoUrl = c.getString(c.getColumnIndex(DatabaseConstants.USER_PHOTO_URL));
|
||||
profile.username = c.getString(c.getColumnIndex(DatabaseConstants.USER_USERNAME));
|
||||
profile.location = c.getString(c.getColumnIndex(DatabaseConstants.USER_LOCATION));
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
@ -36,6 +38,7 @@ public class UserProfile {
|
|||
values.put(DatabaseConstants.USER_PHOTO_URL, photoUrl);
|
||||
values.put(DatabaseConstants.USER_USERID, userId);
|
||||
values.put(DatabaseConstants.USER_USERNAME, username);
|
||||
values.put(DatabaseConstants.USER_LOCATION, location);
|
||||
return values;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,11 +11,13 @@ import android.graphics.Color;
|
|||
import android.graphics.drawable.TransitionDrawable;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.ScaleDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.Html;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -170,7 +172,6 @@ public class ReadingItemFragment extends Fragment implements ClassifierDialogFra
|
|||
}
|
||||
|
||||
private void setupSaveButton() {
|
||||
|
||||
Button saveButton = (Button) view.findViewById(R.id.save_story_button);
|
||||
|
||||
saveButton.setOnClickListener(new OnClickListener() {
|
||||
|
@ -253,7 +254,7 @@ public class ReadingItemFragment extends Fragment implements ClassifierDialogFra
|
|||
itemFeed.setText(feedTitle);
|
||||
}
|
||||
|
||||
itemTitle.setText(story.title);
|
||||
itemTitle.setText(Html.fromHtml(story.title));
|
||||
itemDate.setText(story.longDate);
|
||||
|
||||
if (!TextUtils.isEmpty(story.authors)) {
|
||||
|
@ -413,6 +414,13 @@ public class ReadingItemFragment extends Fragment implements ClassifierDialogFra
|
|||
commentText.setTag("commentBy" + user.id);
|
||||
commentText.setText(sharedText);
|
||||
|
||||
TextView commentLocation = (TextView) commentView.findViewById(R.id.comment_location);
|
||||
if (!TextUtils.isEmpty(user.location)) {
|
||||
commentLocation.setText(user.location.toUpperCase());
|
||||
} else {
|
||||
commentLocation.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (PrefsUtils.getUserImage(getActivity()) != null) {
|
||||
ImageView commentImage = (ImageView) commentView.findViewById(R.id.comment_user_image);
|
||||
commentImage.setImageBitmap(UIUtils.roundCorners(PrefsUtils.getUserImage(getActivity()), 10f));
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.os.AsyncTask;
|
|||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.text.Editable;
|
||||
import android.text.Html;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -108,7 +109,7 @@ public class ShareDialogFragment extends DialogFragment {
|
|||
public void onTextChanged(CharSequence s, int start, int before, int count) { }
|
||||
});
|
||||
|
||||
message.setText(String.format(shareString, story.title));
|
||||
message.setText(String.format(shareString, Html.fromHtml(story.title)));
|
||||
|
||||
if (hasBeenShared) {
|
||||
shareButton.setText(R.string.edit);
|
||||
|
|
|
@ -76,6 +76,12 @@ public class SetupCommentSectionTask extends AsyncTask<Void, Void, Void> {
|
|||
|
||||
while (commentCursor.moveToNext()) {
|
||||
final Comment comment = Comment.fromCursor(commentCursor);
|
||||
|
||||
// skip public comments if they are disabled
|
||||
if (!comment.byFriend && !PrefsUtils.showPublicComments(context)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
View commentView = inflater.inflate(R.layout.include_comment, null);
|
||||
commentView.setTag(COMMENT_VIEW_BY + comment.userId);
|
||||
|
||||
|
@ -87,7 +93,7 @@ public class SetupCommentSectionTask extends AsyncTask<Void, Void, Void> {
|
|||
ImageView commentImage = (ImageView) commentView.findViewById(R.id.comment_user_image);
|
||||
|
||||
TextView commentSharedDate = (TextView) commentView.findViewById(R.id.comment_shareddate);
|
||||
commentSharedDate.setText(comment.sharedDate.toUpperCase() + " AGO");
|
||||
commentSharedDate.setText(comment.sharedDate + " ago");
|
||||
commentSharedDate.setTag(COMMENT_DATE_BY + comment.userId);
|
||||
|
||||
final FlowLayout favouriteContainer = (FlowLayout) commentView.findViewById(R.id.comment_favourite_avatars);
|
||||
|
@ -167,7 +173,7 @@ public class SetupCommentSectionTask extends AsyncTask<Void, Void, Void> {
|
|||
}
|
||||
|
||||
TextView replySharedDate = (TextView) replyView.findViewById(R.id.reply_shareddate);
|
||||
replySharedDate.setText(reply.shortDate.toUpperCase() + " AGO");
|
||||
replySharedDate.setText(reply.shortDate + " ago");
|
||||
|
||||
((LinearLayout) commentView.findViewById(R.id.comment_replies_container)).addView(replyView);
|
||||
}
|
||||
|
@ -179,6 +185,13 @@ public class SetupCommentSectionTask extends AsyncTask<Void, Void, Void> {
|
|||
commentUsername.setText(commentUser.username);
|
||||
String userPhoto = commentUser.photoUrl;
|
||||
|
||||
TextView commentLocation = (TextView) commentView.findViewById(R.id.comment_location);
|
||||
if (!TextUtils.isEmpty(commentUser.location)) {
|
||||
commentLocation.setText(commentUser.location.toUpperCase());
|
||||
} else {
|
||||
commentLocation.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(comment.sourceUserId)) {
|
||||
commentImage.setVisibility(View.INVISIBLE);
|
||||
ImageView usershareImage = (ImageView) commentView.findViewById(R.id.comment_user_reshare_image);
|
||||
|
@ -270,6 +283,7 @@ public class SetupCommentSectionTask extends AsyncTask<Void, Void, Void> {
|
|||
commentCount = commentCount.substring(0, commentCount.length() - 1);
|
||||
}
|
||||
publicCommentTotal.setText(String.format(commentCount, publicCommentViews.size()));
|
||||
viewHolder.get().findViewById(R.id.reading_public_comment_header).setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
if (friendCommentViews.size() > 0) {
|
||||
|
@ -278,6 +292,7 @@ public class SetupCommentSectionTask extends AsyncTask<Void, Void, Void> {
|
|||
commentCount = commentCount.substring(0, commentCount.length() - 1);
|
||||
}
|
||||
friendCommentTotal.setText(String.format(commentCount, friendCommentViews.size()));
|
||||
viewHolder.get().findViewById(R.id.reading_friend_comment_header).setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
for (int i = 0; i < publicCommentViews.size(); i++) {
|
||||
|
|
|
@ -15,6 +15,7 @@ import android.content.Intent;
|
|||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.text.Html;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
@ -260,9 +261,10 @@ public class FeedUtils {
|
|||
Intent intent = new Intent(android.content.Intent.ACTION_SEND);
|
||||
intent.setType("text/plain");
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, story.title);
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, Html.fromHtml(story.title));
|
||||
final String shareString = context.getResources().getString(R.string.share);
|
||||
intent.putExtra(Intent.EXTRA_TEXT, String.format(shareString, new Object[] { story.title, story.permalink }));
|
||||
intent.putExtra(Intent.EXTRA_TEXT, String.format(shareString, new Object[] { Html.fromHtml(story.title),
|
||||
story.permalink }));
|
||||
context.startActivity(Intent.createChooser(intent, "Share using"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,4 +36,6 @@ public class PrefConstants {
|
|||
|
||||
public static final String DEFAULT_STORY_ORDER = "default_story_order";
|
||||
public static final String DEFAULT_READ_FILTER = "default_read_filter";
|
||||
|
||||
public static final String SHOW_PUBLIC_COMMENTS = "show_public_comments";
|
||||
}
|
||||
|
|
|
@ -234,4 +234,9 @@ public class PrefsUtils {
|
|||
private static ReadFilter getDefaultReadFilter(SharedPreferences prefs) {
|
||||
return ReadFilter.valueOf(prefs.getString(PrefConstants.DEFAULT_READ_FILTER, ReadFilter.ALL.toString()));
|
||||
}
|
||||
|
||||
public static boolean showPublicComments(Context context) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
|
||||
return prefs.getBoolean(PrefConstants.SHOW_PUBLIC_COMMENTS, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ gunicorn==0.17.2
|
|||
httplib2==0.8
|
||||
iconv==1.0
|
||||
kombu==2.5.7
|
||||
lxml==3.1.0
|
||||
# lxml==3.1.0
|
||||
mongoengine==0.8.2
|
||||
nltk==2.0.4
|
||||
oauth2==1.5.211
|
||||
|
|
|
@ -3809,7 +3809,7 @@ background: transparent;
|
|||
#story_taskbar .NB-tryfeed-add,
|
||||
#story_taskbar .NB-tryfeed-follow,
|
||||
#story_taskbar .NB-tryout-signup {
|
||||
margin: 6px auto 0px;
|
||||
margin: 2px auto 0px;
|
||||
width: 80px;
|
||||
height: 14px;
|
||||
text-align: center;
|
||||
|
|
|
@ -35,6 +35,7 @@ NEWSBLUR.Modal.prototype = {
|
|||
});
|
||||
setTimeout(function() {
|
||||
// $(window).resize();
|
||||
self.resize();
|
||||
self.flags.modal_loaded = true;
|
||||
});
|
||||
});
|
||||
|
@ -60,6 +61,7 @@ NEWSBLUR.Modal.prototype = {
|
|||
|
||||
resize: function() {
|
||||
// $(window).trigger('resize.simplemodal');
|
||||
$.modal.resize();
|
||||
},
|
||||
|
||||
close: function(callback) {
|
||||
|
|
|
@ -20,6 +20,9 @@ NEWSBLUR.ReaderAccount.prototype.constructor = NEWSBLUR.ReaderAccount;
|
|||
_.extend(NEWSBLUR.ReaderAccount.prototype, {
|
||||
|
||||
runner: function() {
|
||||
this.options.onOpen = _.bind(function() {
|
||||
// $(window).resize();
|
||||
}, this);
|
||||
this.make_modal();
|
||||
this.open_modal();
|
||||
|
||||
|
|
21
media/js/vendor/jquery.simplemodal-1.3.js
vendored
|
@ -82,6 +82,9 @@
|
|||
return $.modal.impl.init(data, options);
|
||||
};
|
||||
|
||||
$.modal.resize = function (callback) {
|
||||
$.modal.impl.resize(callback);
|
||||
};
|
||||
/*
|
||||
* Close the modal dialog.
|
||||
*/
|
||||
|
@ -391,22 +394,24 @@
|
|||
});
|
||||
|
||||
// update window size
|
||||
$(window).bind('resize.simplemodal', function () {
|
||||
$(window).bind('resize.simplemodal', _.bind(this.resize_modal, this));
|
||||
},
|
||||
|
||||
resize_modal: function () {
|
||||
// redetermine the window width/height
|
||||
w = s.getDimensions();
|
||||
w = this.getDimensions();
|
||||
|
||||
// reposition the dialog
|
||||
s.o.autoResize ? s.setContainerDimensions() : s.o.autoPosition && s.setPosition();
|
||||
this.o.autoResize ? this.setContainerDimensions() : this.o.autoPosition && this.setPosition();
|
||||
|
||||
if (ie6 || ieQuirks) {
|
||||
s.fixIE();
|
||||
this.fixIE();
|
||||
}
|
||||
else if (s.o.modal) {
|
||||
else if (this.o.modal) {
|
||||
// update the iframe & overlay
|
||||
s.d.iframe && s.d.iframe.css({height: w[0], width: w[1]});
|
||||
s.d.overlay.css({height: w[0], width: w[1]});
|
||||
this.d.iframe && this.d.iframe.css({height: w[0], width: w[1]});
|
||||
this.d.overlay.css({height: w[0], width: w[1]});
|
||||
}
|
||||
});
|
||||
},
|
||||
/*
|
||||
* Unbind events
|
||||
|
|
|
@ -17,8 +17,10 @@ from vendor import reseekfile
|
|||
# COMMENTS_RE = re.compile('\<![ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t]*)\>')
|
||||
COMMENTS_RE = re.compile('\<!--.*?--\>')
|
||||
|
||||
def midnight_today():
|
||||
return datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
def midnight_today(now=None):
|
||||
if not now:
|
||||
now = datetime.datetime.now()
|
||||
return now.replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=None)
|
||||
|
||||
def midnight_yesterday(midnight=None):
|
||||
if not midnight:
|
||||
|
@ -28,9 +30,11 @@ def midnight_yesterday(midnight=None):
|
|||
def beginning_of_this_month():
|
||||
return datetime.datetime.now().replace(day=1, hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
def format_story_link_date__short(date):
|
||||
def format_story_link_date__short(date, now=None):
|
||||
if not now:
|
||||
now = datetime.datetime.now()
|
||||
date = date.replace(tzinfo=None)
|
||||
midnight = midnight_today()
|
||||
midnight = midnight_today(now)
|
||||
if date > midnight:
|
||||
return date.strftime('%I:%M%p').lstrip('0').lower()
|
||||
elif date > midnight_yesterday(midnight):
|
||||
|
|