diff --git a/apps/profile/models.py b/apps/profile/models.py index 038c99742..783ffac8e 100644 --- a/apps/profile/models.py +++ b/apps/profile/models.py @@ -162,7 +162,7 @@ class Profile(models.Model): def activate_premium(self, never_expire=False): from apps.profile.tasks import EmailNewPremium - + EmailNewPremium.delay(user_id=self.user.pk) self.is_premium = True @@ -357,9 +357,10 @@ class Profile(models.Model): stripe_cancel = self.cancel_premium_stripe() return paypal_cancel or stripe_cancel - def cancel_premium_paypal(self): + def cancel_premium_paypal(self, second_most_recent_only=False): transactions = PayPalIPN.objects.filter(custom=self.user.username, - txn_type='subscr_signup') + txn_type='subscr_signup').order_by('-subscr_date') + if not transactions: return @@ -371,14 +372,24 @@ class Profile(models.Model): 'API_CA_CERTS': False, } paypal = PayPalInterface(**paypal_opts) - transaction = transactions[0] + if second_most_recent_only: + # Check if user has an active subscription. If so, cancel it because a new one came in. + if len(transactions) > 1: + transaction = transactions[1] + else: + return False + else: + transaction = transactions[0] profileid = transaction.subscr_id try: paypal.manage_recurring_payments_profile_status(profileid=profileid, action='Cancel') except PayPalAPIResponseError: - logging.user(self.user, "~FRUser ~SBalready~SN canceled Paypal subscription") + logging.user(self.user, "~FRUser ~SBalready~SN canceled Paypal subscription: %s" % profileid) else: - logging.user(self.user, "~FRCanceling Paypal subscription") + if second_most_recent_only: + logging.user(self.user, "~FRCanceling ~BR~FWsecond-oldest~SB~FR Paypal subscription: %s" % profileid) + else: + logging.user(self.user, "~FRCanceling Paypal subscription: %s" % profileid) return True @@ -883,6 +894,8 @@ def paypal_signup(sender, **kwargs): except: pass user.profile.activate_premium() + user.profile.cancel_premium_stripe() + user.profile.cancel_premium_paypal(second_most_recent_only=True) subscription_signup.connect(paypal_signup) def paypal_payment_history_sync(sender, **kwargs): @@ -931,6 +944,7 @@ def stripe_signup(sender, full_json, **kwargs): profile = Profile.objects.get(stripe_id=stripe_id) logging.user(profile.user, "~BC~SB~FBStripe subscription signup") profile.activate_premium() + profile.cancel_premium_paypal() except Profile.DoesNotExist: return {"code": -1, "message": "User doesn't exist."} zebra_webhook_customer_subscription_created.connect(stripe_signup) diff --git a/apps/profile/views.py b/apps/profile/views.py index edceb05f4..867cec9b1 100644 --- a/apps/profile/views.py +++ b/apps/profile/views.py @@ -419,10 +419,14 @@ def payment_history(request): "read_story_count": RUserStory.read_story_count(user.pk), "feed_opens": UserSubscription.objects.filter(user=user).aggregate(sum=Sum('feed_opens'))['sum'], "training": { - 'title': MClassifierTitle.objects.filter(user_id=user.pk).count(), - 'tag': MClassifierTag.objects.filter(user_id=user.pk).count(), - 'author': MClassifierAuthor.objects.filter(user_id=user.pk).count(), - 'feed': MClassifierFeed.objects.filter(user_id=user.pk).count(), + 'title_ps': MClassifierTitle.objects.filter(user_id=user.pk, score__gt=0).count(), + 'title_ng': MClassifierTitle.objects.filter(user_id=user.pk, score__lt=0).count(), + 'tag_ps': MClassifierTag.objects.filter(user_id=user.pk, score__gt=0).count(), + 'tag_ng': MClassifierTag.objects.filter(user_id=user.pk, score__lt=0).count(), + 'author_ps': MClassifierAuthor.objects.filter(user_id=user.pk, score__gt=0).count(), + 'author_ng': MClassifierAuthor.objects.filter(user_id=user.pk, score__lt=0).count(), + 'feed_ps': MClassifierFeed.objects.filter(user_id=user.pk, score__gt=0).count(), + 'feed_ng': MClassifierFeed.objects.filter(user_id=user.pk, score__lt=0).count(), } } diff --git a/clients/android/NewsBlur/src/com/newsblur/util/FeedUtils.java b/clients/android/NewsBlur/src/com/newsblur/util/FeedUtils.java index 2a65582a5..4d102df54 100644 --- a/clients/android/NewsBlur/src/com/newsblur/util/FeedUtils.java +++ b/clients/android/NewsBlur/src/com/newsblur/util/FeedUtils.java @@ -53,7 +53,13 @@ public class FeedUtils { new AsyncTask() { @Override protected Void doInBackground(Void... arg) { - dbHelper.clearStorySession(); + try { + dbHelper.clearStorySession(); + } catch (Exception e) { + ; // TODO: this can evade DB-ready gating and crash. figure out how to + // defer this call until the DB-ready broadcast is received, as this + // can mask important errors + } return null; } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); diff --git a/media/css/reader.css b/media/css/reader.css index 5e770e2ce..5a779e2ac 100644 --- a/media/css/reader.css +++ b/media/css/reader.css @@ -7818,6 +7818,12 @@ form.opml_import_form input { .NB-modal-admin .NB-admin-training-counts span.NB-grey { color: #D0D0D0; } +.NB-modal-admin .NB-admin-training-counts span.NB-green { + color: #2B8B19; +} +.NB-modal-admin .NB-admin-training-counts span.NB-red { + color: #761113; +} /* ===================== */ /* = Email Story Modal = */ diff --git a/media/js/newsblur/reader/reader_admin.js b/media/js/newsblur/reader/reader_admin.js index 4e7febd99..cf69ebbac 100644 --- a/media/js/newsblur/reader/reader_admin.js +++ b/media/js/newsblur/reader/reader_admin.js @@ -87,7 +87,8 @@ _.extend(NEWSBLUR.ReaderUserAdmin.prototype, { $actions.append($.make('div', { className: "NB-modal-submit-button NB-modal-submit-green NB-admin-action-history", style: "float: left" }, "Update History")); $actions.append($.make('div', { className: "NB-modal-submit-button NB-modal-submit-green NB-admin-action-opml", style: "float: left" }, "OPML")); - + + var training = data.statistics.training; $statistics.append($.make('dl', [ $.make('dt', 'Created:'), $.make('dd', data.statistics.created_date), @@ -109,10 +110,30 @@ _.extend(NEWSBLUR.ReaderUserAdmin.prototype, { $.make('dd', Inflector.commas(data.statistics.read_story_count)), $.make('dt', 'Training:'), $.make('dd', { className: 'NB-admin-training-counts' }, [ - $.make('span', { className: data.statistics.training.title ? '' : 'NB-grey' }, 'Title: ' + data.statistics.training.title), - $.make('span', { className: data.statistics.training.author ? '' : 'NB-grey' }, 'Author: ' + data.statistics.training.author), - $.make('span', { className: data.statistics.training.tag ? '' : 'NB-grey' }, 'Tag: ' + data.statistics.training.tag), - $.make('span', { className: data.statistics.training.feed ? '' : 'NB-grey' }, 'Feed: ' + data.statistics.training.feed) + $.make('span', { className: training.title_ps || training.title_ng ? '' : 'NB-grey' }, [ + 'Title: ', + (training.title_ps && $.make('span', { className: 'NB-green' }, training.title_ps)), + '-', + (training.title_ng && $.make('span', { className: 'NB-red' }, training.title_ng)) + ]), + $.make('span', { className: training.author_ps || training.author_ng ? '' : 'NB-grey' }, [ + 'Author: ', + (training.author_ps && $.make('span', { className: 'NB-green' }, training.author_ps)), + '-', + (training.author_ng && $.make('span', { className: 'NB-red' }, training.author_ng)) + ]), + $.make('span', { className: training.tag_ps || training.tag_ng ? '' : 'NB-grey' }, [ + 'Tag: ', + (training.tag_ps && $.make('span', { className: 'NB-green' }, training.tag_ps)), + '-', + (training.tag_ng && $.make('span', { className: 'NB-red' }, training.tag_ng)) + ]), + $.make('span', { className: training.feed_ps || training.feed_ng ? '' : 'NB-grey' }, [ + 'Feed: ', + (training.feed_ps && $.make('span', { className: 'NB-green' }, training.feed_ps)), + '-', + (training.feed_ng && $.make('span', { className: 'NB-red' }, training.feed_ng)) + ]) ]) ])); $(window).resize(); diff --git a/media/js/newsblur/reader/reader_feedchooser.js b/media/js/newsblur/reader/reader_feedchooser.js index 44f02b7b4..bbc1377fc 100644 --- a/media/js/newsblur/reader/reader_feedchooser.js +++ b/media/js/newsblur/reader/reader_feedchooser.js @@ -77,7 +77,8 @@ _.extend(NEWSBLUR.ReaderFeedchooser.prototype, { $.make('b', { style: 'display: block; margin: 8px 0' }, [ $.make('span', { className: 'NB-raquo' }, '»'), ' ', - NEWSBLUR.Globals.premium_expire && NEWSBLUR.utils.format_date(NEWSBLUR.Globals.premium_expire) + NEWSBLUR.Globals.premium_expire && NEWSBLUR.utils.format_date(NEWSBLUR.Globals.premium_expire), + (!NEWSBLUR.Globals.premium_expire && $.make('b', "Never gonna expire. Congrats!")) ]), 'You can change your payment method and card details. ', (NEWSBLUR.Globals.premium_expire < new Date) ? diff --git a/templates/mail/email_base.xhtml b/templates/mail/email_base.xhtml index 721aa4c96..8a22168a6 100644 --- a/templates/mail/email_base.xhtml +++ b/templates/mail/email_base.xhtml @@ -36,23 +36,23 @@

Stay up to date and in touch with a few different ways:

{% block resources_header %}To get the most out of NewsBlur, here are a few resources:{% endblock resources_header %}

There are plenty of ways to use NewsBlur beyond the web:

diff --git a/utils/feed_fetcher.py b/utils/feed_fetcher.py index a65cd5b99..9992ab282 100644 --- a/utils/feed_fetcher.py +++ b/utils/feed_fetcher.py @@ -130,7 +130,7 @@ class FetchFeed: self.fpf = feedparser.parse(smart_unicode(raw_feed.content), response_headers=response_headers) except Exception, e: - logging.debug(" ---> [%-30s] ~FRFeed failed to fetch with request, trying feedparser: %s" % (self.feed.title[:30], e)) + logging.debug(" ---> [%-30s] ~FRFeed failed to fetch with request, trying feedparser: %s" % (self.feed.title[:30], unicode(e)[:100])) if not self.fpf: try: diff --git a/utils/feedfinder2.py b/utils/feedfinder2.py index 0fe4aee5d..87dd649b7 100755 --- a/utils/feedfinder2.py +++ b/utils/feedfinder2.py @@ -49,7 +49,7 @@ class FeedFinder(object): def is_feed_data(self, text): data = text.lower() - if data.count(" tags. logging.info("Looking for tags.") - tree = BeautifulSoup(text) + tree = BeautifulSoup(feed_text) links = [] for link in tree.findAll("link"): if link.get("type") in ["application/rss+xml",