mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-09-18 21:50:56 +00:00
Merge branch 'master' into 5.1
* master: Maybe I shouldn't be coding right now. That errant 'else' keyword looked fine in word wrap. Python's naming on the try..except..else block is almost as bad as for..else. I blame Python for this stupidity. Lifetime premium accounts should see status when on Renewal dialog. Adding auto-canceling of stripe/paypal subscription when renewing with different paypal/stripe provider. Splitting intelligence trainer counts into + and - Adding alt attributes to images in emails to lower spam score. Fix somewhat long-standing error logging bug that spits out a ton of data on feeds that don't work with requests lib. Fix on-upgrade crash. Fixing feed finder to allow feeds with <html> tags, just not those right at the beginning.
This commit is contained in:
commit
b54a583c9d
9 changed files with 82 additions and 30 deletions
|
@ -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)
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,13 @@ public class FeedUtils {
|
|||
new AsyncTask<Void, Void, Void>() {
|
||||
@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);
|
||||
|
|
|
@ -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 = */
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) ?
|
||||
|
|
|
@ -36,23 +36,23 @@
|
|||
<p style="line-height:20px;">Stay up to date and in touch with a few different ways:</p>
|
||||
<p style="line-height: 20px;">
|
||||
<ul style="list-style: none;">
|
||||
<li style="line-height:22px;"><a href="http://twitter.com/newsblur/" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/icons/circular/story_share_twitter_active.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Follow @newsblur on Twitter</a></li>
|
||||
<li style="line-height:22px;"><a href="http://github.com/samuelclay/" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/welcome/github_favicon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Follow @samuelclay on GitHub</a></li>
|
||||
<li style="line-height:22px;"><a href="http://twitter.com/newsblur/" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/icons/circular/story_share_twitter_active.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;" alt=""> Follow @newsblur on Twitter</a></li>
|
||||
<li style="line-height:22px;"><a href="http://github.com/samuelclay/" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/welcome/github_favicon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;" alt=""> Follow @samuelclay on GitHub</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p style="line-height: 20px;">{% block resources_header %}To get the most out of NewsBlur, here are a few resources:{% endblock resources_header %}</p>
|
||||
<p style="line-height: 20px;">
|
||||
<ul style="list-style: none;">
|
||||
<li style="line-height:22px;"><a href="http://blog.newsblur.com" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/favicon_32.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Read the NewsBlur Blog</a></li>
|
||||
<li style="line-height:22px;"><a href="http://getsatisfaction.com/newsblur/" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/reader/getsatisfaction.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Get support on NewsBlur's Get Satisfaction</a></li>
|
||||
<li style="line-height:22px;"><a href="http://blog.newsblur.com" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/favicon_32.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;" alt=""> Read the NewsBlur Blog</a></li>
|
||||
<li style="line-height:22px;"><a href="http://getsatisfaction.com/newsblur/" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/reader/getsatisfaction.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;" alt=""> Get support on NewsBlur's Get Satisfaction</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p style="line-height: 20px;">There are plenty of ways to use NewsBlur beyond the web:</p>
|
||||
<p style="line-height: 20px;">
|
||||
<ul style="list-style: none;">
|
||||
<li style="line-height:22px;"><a href="http://{% current_domain %}/ios/" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/reader/iphone_icon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Download the free iPad/iPhone App</a></li>
|
||||
<li style="line-height:22px;"><a href="http://{% current_domain %}/android/" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/reader/android_icon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Download the free Android App</a></li>
|
||||
<li style="line-height:22px;"><a href="http://{% current_domain %}{{ user.profile.autologin_url }}?next=goodies" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/icons/silk/package_green.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Download browser extensions for Safari, Firefox, and Chrome</a></li>
|
||||
<li style="line-height:22px;"><a href="http://{% current_domain %}/ios/" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/reader/iphone_icon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;" alt=""> Download the free iPad/iPhone App</a></li>
|
||||
<li style="line-height:22px;"><a href="http://{% current_domain %}/android/" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/reader/android_icon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;" alt=""> Download the free Android App</a></li>
|
||||
<li style="line-height:22px;"><a href="http://{% current_domain %}{{ user.profile.autologin_url }}?next=goodies" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/icons/silk/package_green.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;" alt=""> Download browser extensions for Safari, Firefox, and Chrome</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
</td>
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -49,7 +49,7 @@ class FeedFinder(object):
|
|||
|
||||
def is_feed_data(self, text):
|
||||
data = text.lower()
|
||||
if data.count("<html"):
|
||||
if data and data[:100].count("<html"):
|
||||
return False
|
||||
return data.count("<rss")+data.count("<rdf")+data.count("<feed")
|
||||
|
||||
|
@ -75,17 +75,17 @@ def find_feeds(url, check_all=False, user_agent=None):
|
|||
url = coerce_url(url)
|
||||
|
||||
# Download the requested URL.
|
||||
text = finder.get_feed(url)
|
||||
if text is None:
|
||||
feed_text = finder.get_feed(url)
|
||||
if feed_text is None:
|
||||
return []
|
||||
|
||||
# Check if it is already a feed.
|
||||
if finder.is_feed_data(text):
|
||||
if finder.is_feed_data(feed_text):
|
||||
return [url]
|
||||
|
||||
# Look for <link> tags.
|
||||
logging.info("Looking for <link> tags.")
|
||||
tree = BeautifulSoup(text)
|
||||
tree = BeautifulSoup(feed_text)
|
||||
links = []
|
||||
for link in tree.findAll("link"):
|
||||
if link.get("type") in ["application/rss+xml",
|
||||
|
|
Loading…
Add table
Reference in a new issue