Adding a paypal archive return page. Also redrawing when premium expire/renewal status changes on payment fetch in account dialog.

This commit is contained in:
Samuel Clay 2022-04-06 15:56:13 -04:00
parent e44ed2b46b
commit b90501d955
10 changed files with 167 additions and 38 deletions

View file

@ -179,6 +179,8 @@ deploy_staging:
staging: deploy_staging
celery_stop:
- ansible-playbook ansible/deploy.yml -l task --tags stop
sentry:
- ansible-playbook ansible/setup.yml -l sentry -t sentry
maintenance_on:
- ansible-playbook ansible/deploy.yml -l web --tags maintenance_on
maintenance_off:

View file

@ -1,7 +1,13 @@
---
- name: reload sentry
become: yes
command:
chdir: /srv/sentry/
cmd: ./install.sh
block:
- name: Updating Sentry
command:
chdir: /srv/sentry/
cmd: ./install.sh
- name: docker-compuse up -d
command:
chdir: /srv/sentry/
cmd: docker-compose up -d
listen: reload sentry

View file

@ -1,5 +1,6 @@
import time
import datetime
from wsgiref.util import application_uri
import dateutil
import stripe
import hashlib
@ -414,15 +415,21 @@ class Profile(models.Model):
paypal_api = self.paypal_api()
if not paypal_api:
return
paypal_return = reverse('paypal-return')
if plan == "archive":
paypal_return = reverse('paypal-archive-return')
try:
application_context = {
'shipping_preference': 'NO_SHIPPING',
}
if settings.DEBUG:
application_context['return_url'] = f"https://73ee-71-233-245-159.ngrok.io{paypal_return}"
else:
application_context['return_url'] = f"https://{Site.objects.get_current().domain}{paypal_return}"
paypal_subscription = paypal_api.post(f'/v1/billing/subscriptions/{self.paypal_sub_id}/revise', {
'plan_id': Profile.plan_to_paypal_plan_id(plan),
'application_context': {
'shipping_preference': 'NO_SHIPPING',
'return_url': f"https://{Site.objects.get_current().domain}{reverse('paypal-return')}"
# 'return_url': f"https://bb4a-71-233-245-159.ngrok.io{reverse('paypal-return')}"
},
'application_context': application_context,
})
except paypalrestsdk.ResourceNotFound:
logging.user(self.user, f"~FRCouldn't find paypal payments: {self.paypal_sub_id} {plan}")
@ -488,9 +495,12 @@ class Profile(models.Model):
start_date = datetime.datetime(2009, 1, 1).strftime("%Y-%m-%dT%H:%M:%SZ")
end_date = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
transactions = paypal_api.get(f"/v1/billing/subscriptions/{paypal_id}/transactions?start_time={start_date}&end_time={end_date}")
if 'transactions' not in transactions:
logging.user(self.user, f"~FRCouldn't find paypal transactions: {paypal_id}")
try:
transactions = paypal_api.get(f"/v1/billing/subscriptions/{paypal_id}/transactions?start_time={start_date}&end_time={end_date}")
except paypalrestsdk.exceptions.ResourceNotFound:
transactions = None
if not transactions or 'transactions' not in transactions:
logging.user(self.user, f"~FRCouldn't find paypal transactions: ~SB{paypal_id}")
continue
for transaction in transactions['transactions']:
created = dateutil.parser.parse(transaction['time'])
@ -567,7 +577,10 @@ class Profile(models.Model):
self.save()
if self.premium_renewal != premium_renewal or self.active_provider != active_provider:
logging.user(self.user, "~FCTurning ~SB~%s~SN~FC premium renewal (%s)" % ("FRoff" if not premium_renewal else "FBon", active_provider))
active_sub_id = self.stripe_id
if active_provider == "paypal":
active_sub_id = self.paypal_sub_id
logging.user(self.user, "~FCTurning ~SB~%s~SN~FC premium renewal (%s: %s)" % ("FRoff" if not premium_renewal else "FBon", active_provider, active_sub_id))
self.premium_renewal = premium_renewal
self.active_provider = active_provider
self.save()
@ -1562,8 +1575,7 @@ def paypal_signup(sender, **kwargs):
user.profile.cancel_premium_stripe()
# user.profile.cancel_premium_paypal(second_most_recent_only=True)
# Shouldn't be here anymore as the new Paypal REST API uses webhooks
assert False
assert False, "Shouldn't be here anymore as the new Paypal REST API uses webhooks"
valid_ipn_received.connect(paypal_signup)
def paypal_payment_history_sync(sender, **kwargs):

View file

@ -11,10 +11,12 @@ urlpatterns = [
url(r'^set_collapsed_folders/?', views.set_collapsed_folders),
url(r'^paypal_form/?', views.paypal_form),
url(r'^paypal_return/?', views.paypal_return, name='paypal-return'),
url(r'^paypal_archive_return/?', views.paypal_archive_return, name='paypal-archive-return'),
url(r'^stripe_return/?', views.paypal_return, name='stripe-return'),
url(r'^switch_stripe_subscription/?', views.switch_stripe_subscription, name='switch-stripe-subscription'),
url(r'^switch_paypal_subscription/?', views.switch_paypal_subscription, name='switch-paypal-subscription'),
url(r'^is_premium/?', views.profile_is_premium, name='profile-is-premium'),
url(r'^is_premium_archive/?', views.profile_is_premium_archive, name='profile-is-premium-archive'),
url(r'^paypal_ipn/?', include('paypal.standard.ipn.urls'), name='paypal-ipn'),
url(r'^paypal_webhooks/?', views.paypal_webhooks, name='paypal-webhooks'),
url(r'^stripe_form/?', views.stripe_form, name='stripe-form'),

View file

@ -321,6 +321,13 @@ def paypal_return(request):
'user_profile': request.user.profile,
})
@login_required
def paypal_archive_return(request):
return render(request, 'reader/paypal_archive_return.xhtml', {
'user_profile': request.user.profile,
})
@login_required
def activate_premium(request):
return HttpResponseRedirect(reverse('index'))
@ -348,6 +355,36 @@ def profile_is_premium(request):
return {
'is_premium': profile.is_premium,
'is_premium_archive': profile.is_archive,
'code': code,
'activated_subs': activated_subs,
'total_subs': total_subs,
}
@ajax_login_required
@json.json_view
def profile_is_premium_archive(request):
# Check tries
code = 0
retries = int(request.GET['retries'])
profile = Profile.objects.get(user=request.user)
subs = UserSubscription.objects.filter(user=request.user)
total_subs = subs.count()
activated_subs = subs.filter(active=True).count()
if retries >= 30:
code = -1
if not request.user.profile.is_premium:
subject = "Premium activation failed: %s (%s/%s)" % (request.user, activated_subs, total_subs)
message = """User: %s (%s) -- Email: %s""" % (request.user.username, request.user.pk, request.user.email)
mail_admins(subject, message)
request.user.profile.is_premium = True
request.user.profile.save()
return {
'is_premium': profile.is_premium,
'is_premium_archive': profile.is_archive,
'code': code,
'activated_subs': activated_subs,
'total_subs': total_subs,
@ -539,7 +576,10 @@ def switch_paypal_subscription(request):
if approve_url:
return HttpResponseRedirect(approve_url)
return HttpResponseRedirect(reverse('paypal-return'))
paypal_return = reverse('paypal-return')
if plan == "archive":
paypal_return = reverse('paypal-archive-return')
return HttpResponseRedirect(paypal_return)
@login_required
def stripe_checkout(request):

View file

@ -8,9 +8,14 @@
NEWSBLUR.PaypalReturn = function() {
this.retries = 0;
_.delay(_.bind(function() {
this.detect_premium();
setInterval(_.bind(function() { this.detect_premium(); }, this), 1500);
_.delay(_.bind(function () {
if (_.string.include(window.location.pathname, 'paypal_archive')) {
this.detect_premium_archive();
setInterval(_.bind(function() { this.detect_premium_archive(); }, this), 2000);
} else {
this.detect_premium();
setInterval(_.bind(function() { this.detect_premium(); }, this), 2000);
}
}, this), 2000);
};
@ -23,9 +28,38 @@
'dataType' : 'json',
'success' : _.bind(function(resp) {
// NEWSBLUR.log(['resp', resp]);
if ((resp.activated_subs >= resp.total_subs || resp.code < 0)) {
if (resp.code < 0) {
this.homepage();
} else if (resp.activated_subs != resp.total_subs) {
} else if ((resp.activated_subs >= resp.total_subs && resp.is_premium)) {
this.homepage();
} else if (resp.activated_subs != resp.total_subs || !resp.is_premium) {
this.retries += 1;
$('.NB-paypal-return-loading').progressbar({
value: (resp.activated_subs / resp.total_subs) * 100
});
}
}, this),
'error' : _.bind(function() {
this.retries += 1;
if (this.retries > 30) {
this.homepage();
}
}, this)
});
},
detect_premium_archive: function() {
$.ajax({
'url' : '/profile/is_premium_archive',
'data' : {'retries': this.retries},
'dataType' : 'json',
'success' : _.bind(function(resp) {
// NEWSBLUR.log(['resp', resp]);
if (resp.code < 0) {
this.homepage();
} else if ((resp.activated_subs >= resp.total_subs && resp.is_premium_archive)) {
this.homepage();
} else if (resp.activated_subs != resp.total_subs || !resp.is_premium_archive) {
this.retries += 1;
$('.NB-paypal-return-loading').progressbar({
value: (resp.activated_subs / resp.total_subs) * 100

View file

@ -164,14 +164,8 @@ _.extend(NEWSBLUR.ReaderAccount.prototype, {
]),
(NEWSBLUR.Globals.is_premium && $.make('div', { className: 'NB-preference NB-preference-premium-renew' }, [
$.make('div', { className: 'NB-preference-options' }, [
(NEWSBLUR.Globals.premium_renewal && $.make('div', { className: 'NB-block' }, 'Your premium account is paid until:')),
(!NEWSBLUR.Globals.premium_renewal && $.make('div', { className: 'NB-block' }, 'Your premium account will downgrade on:')),
$.make('div', { className: 'NB-block' }, [
$.make('span', { className: 'NB-raquo' }, '&raquo;'),
' ',
(NEWSBLUR.Globals.premium_expire && NEWSBLUR.utils.format_date(NEWSBLUR.Globals.premium_expire)),
(!NEWSBLUR.Globals.premium_expire && $.make('b', "Never gonna expire. Congrats!"))
]),
$.make('div', { className: "NB-premium-renewal-details-container" }, this.make_premium_renewal_details()),
$.make('div', { className: 'NB-block NB-premium-expire-container' }, this.make_premium_expire()),
$.make('a', { href: '#', className: 'NB-block NB-account-premium-renew NB-modal-submit-button NB-modal-submit-green' }, 'Change your credit card')
]),
$.make('div', { className: 'NB-preference-label'}, [
@ -189,11 +183,7 @@ _.extend(NEWSBLUR.ReaderAccount.prototype, {
])
]),
(NEWSBLUR.Globals.is_premium && $.make('div', { className: 'NB-preference NB-preference-premium-cancel' }, [
$.make('div', { className: 'NB-preference-options' }, [
(NEWSBLUR.Globals.premium_renewal && $.make('a', { href: '#', className: 'NB-block NB-account-premium-cancel NB-modal-submit-button NB-modal-submit-red' }, 'Cancel subscription renewal')),
(!NEWSBLUR.Globals.premium_renewal && "Your subscription is no longer active."),
(!NEWSBLUR.Globals.premium_renewal && $.make('a', { href: '#', className: 'NB-block NB-account-premium-renew NB-modal-submit-button NB-modal-submit-green' }, 'Restart your subscription'))
]),
$.make('div', { className: 'NB-preference-options NB-premium-renewal-container' }, this.make_premium_renewal()),
$.make('div', { className: 'NB-preference-label'}, [
'Premium renewal'
])
@ -462,9 +452,47 @@ _.extend(NEWSBLUR.ReaderAccount.prototype, {
});
},
fetch_payment_history: function() {
make_premium_expire: function () {
return $.make('div', [
$.make('span', { className: 'NB-raquo' }, '&raquo;'),
' ',
(NEWSBLUR.Globals.premium_expire && NEWSBLUR.utils.format_date(NEWSBLUR.Globals.premium_expire)),
(!NEWSBLUR.Globals.premium_expire && $.make('b', "Never gonna expire. Congrats!"))
]);
},
make_premium_renewal: function () {
return $.make('div', [
(NEWSBLUR.Globals.premium_renewal && $.make('a', { href: '#', className: 'NB-block NB-account-premium-cancel NB-modal-submit-button NB-modal-submit-red' }, 'Cancel subscription renewal')),
(!NEWSBLUR.Globals.premium_renewal && "Your subscription is no longer active."),
(!NEWSBLUR.Globals.premium_renewal && $.make('a', { href: '#', className: 'NB-block NB-account-premium-renew NB-modal-submit-button NB-modal-submit-green' }, 'Restart your subscription'))
]);
},
make_premium_renewal_details: function () {
return $.make('div', [
(NEWSBLUR.Globals.premium_renewal && $.make('div', { className: 'NB-block' }, 'Your premium account is paid until:')),
(!NEWSBLUR.Globals.premium_renewal && $.make('div', { className: 'NB-block' }, 'Your premium account will downgrade on:'))
]);
},
fetch_payment_history: function () {
this.model.fetch_payment_history(NEWSBLUR.Globals.user_id, _.bind(function(data) {
var $history = $('.NB-account-payments', this.$modal).empty();
if (NEWSBLUR.Globals.premium_renewal != data.premium_renewal) {
NEWSBLUR.Globals.premium_renewal = data.premium_renewal;
$(".NB-premium-renewal-container", this.$modal).html(this.make_premium_renewal());
$(".NB-premium-renewal-details-container", this.$modal).html(this.make_premium_renewal_details());
}
if (NEWSBLUR.Globals.premium_expire != data.premium_expire) {
if (data.premium_expire) {
NEWSBLUR.Globals.premium_expire = new Date(data.premium_expire);
$(".NB-premium-expire-container", this.$modal).html(this.make_premium_expire());
}
}
if (!data.payments || !data.payments.length) {
$history.append($.make('li', { className: 'NB-account-payment' }, [
$.make('i', 'No payments found.')

View file

@ -364,7 +364,11 @@ _.extend(NEWSBLUR.ReaderFeedchooser.prototype, {
onApprove: function (data, actions) {
// Full available details
console.log('Paypal approve result', data.subscriptionID, JSON.stringify(data, null, 2));
actions.redirect(NEWSBLUR.URLs.paypal_return);
if (plan == "archive") {
actions.redirect(NEWSBLUR.URLs.paypal_archive_return);
} else {
actions.redirect(NEWSBLUR.URLs.paypal_return);
}
},
onError: function (err) {

View file

@ -21,7 +21,7 @@ SESSION_COOKIE_DOMAIN = 'localhost'
DOCKERBUILD = True
DEBUG = False
DEBUG = True
# DEBUG = True
# DEBUG_ASSETS controls JS/CSS asset packaging. Turning this off requires you to run
# `./manage.py collectstatic` first. Turn this on for development so you can see

View file

@ -121,7 +121,8 @@
'delete-account' : "{% url "profile-delete-account" %}",
'folder_rss' : "/reader/folder_rss/{user_id}/{secret_token}/{unread_filter}/{folder_title}",
'paypal_checkout_js' : 'https://www.paypal.com/sdk/js?vault=true&intent=subscription&client-id={% settings_value "PAYPAL_API_CLIENTID" %}',
'paypal_return' : "https://{% current_domain %}{% url "paypal-return" %}"
'paypal_return' : "https://{% current_domain %}{% url "paypal-return" %}",
'paypal_archive_return' : "https://{% current_domain %}{% url "paypal-archive-return" %}"
};
NEWSBLUR.Models = {};
NEWSBLUR.Collections = {};