Merge branch 'master' of https://github.com/Gluejar/regluit
commit
f7282d4e11
|
@ -62,7 +62,7 @@ class BookLoaderTests(TestCase):
|
||||||
models.Identifier(type='isbn', value='9780226032030', work=w, edition=e).save()
|
models.Identifier(type='isbn', value='9780226032030', work=w, edition=e).save()
|
||||||
bookloader.update_edition(e)
|
bookloader.update_edition(e)
|
||||||
self.assertEqual(e.work.language, 'en')
|
self.assertEqual(e.work.language, 'en')
|
||||||
self.assertEqual(e.title, 'Forbidden journeys')
|
self.assertEqual(e.title, 'Forbidden Journeys')
|
||||||
|
|
||||||
def test_double_add(self):
|
def test_double_add(self):
|
||||||
bookloader.add_by_isbn('0441012035')
|
bookloader.add_by_isbn('0441012035')
|
||||||
|
|
|
@ -1 +1,81 @@
|
||||||
# Create your views here.
|
from regluit.core.models import Campaign
|
||||||
|
from django.http import HttpResponse
|
||||||
|
import traceback
|
||||||
|
from django.db import transaction
|
||||||
|
import time
|
||||||
|
|
||||||
|
def test_read(request):
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
row_id = 1
|
||||||
|
|
||||||
|
print "Attempting to read row"
|
||||||
|
|
||||||
|
# A read the waits for the exclusive lock for the row
|
||||||
|
campaign = Campaign.objects.raw("SELECT * FROM core_campaign WHERE id=%d FOR UPDATE" % row_id)[0]
|
||||||
|
|
||||||
|
print "Successfully read row data %d" % campaign.target
|
||||||
|
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
return HttpResponse("Success")
|
||||||
|
|
||||||
|
def test_write(request):
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
row_id = 1
|
||||||
|
campaign = Campaign.objects.get(id=row_id)
|
||||||
|
|
||||||
|
print "Attempting to write row via ordinary ORM"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Modify the data. This will block if any shared lock (Either FOR UPDATE or LOCK IN SHARED MODE is held
|
||||||
|
#
|
||||||
|
campaign.target = campaign.target + 10
|
||||||
|
campaign.save()
|
||||||
|
|
||||||
|
print "Successfully write new row data %d" % campaign.target
|
||||||
|
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
return HttpResponse("Success")
|
||||||
|
|
||||||
|
@transaction.commit_on_success
|
||||||
|
def test_lock(request):
|
||||||
|
|
||||||
|
try:
|
||||||
|
row_id = 1
|
||||||
|
|
||||||
|
print "Attempting to acquire row lock"
|
||||||
|
|
||||||
|
campaign = Campaign.objects.raw("SELECT * FROM core_campaign WHERE id=%d FOR UPDATE" % row_id)[0]
|
||||||
|
|
||||||
|
print "Row lock acquired, modifying data"
|
||||||
|
|
||||||
|
# Modify the data
|
||||||
|
campaign.target = campaign.target + 10
|
||||||
|
campaign.save()
|
||||||
|
|
||||||
|
#
|
||||||
|
# test by sleeping here for 10 seconds.
|
||||||
|
#
|
||||||
|
# The FOR UPDATE request will lock the row exclusively. All write/delete operations require a compatible lock
|
||||||
|
# and will block until this transaction is complete. Some reads will block, but some will not. If we want to
|
||||||
|
# block the read until this transaction is complete, the read should also acquire an exlusive OR a shared lock.
|
||||||
|
#
|
||||||
|
# As soon as the function completes, the transaction will be committed and the lock released.
|
||||||
|
# You can modify the commit_on_success decorator to get different transaction behaviors
|
||||||
|
#
|
||||||
|
print "Thread sleeping for 10 seconds"
|
||||||
|
time.sleep(10)
|
||||||
|
print "Thread sleep complete"
|
||||||
|
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
return HttpResponse("Success")
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<b>UNGLUE IT!</b>
|
<b>UNGLUE IT!</b>
|
||||||
<p><b>${{ work.last_campaign.current_total|floatformat:0|intcomma }}</b> raised</p>
|
<p><b>${{ work.last_campaign.current_total|floatformat:0|intcomma }}</b> raised</p>
|
||||||
<p><b>${{ work.last_campaign.target|floatformat:0|intcomma }}</b> needed</p>
|
<p><b>${{ work.last_campaign.target|floatformat:0|intcomma }}</b> needed</p>
|
||||||
<p>by {{ deadline|date:"M d, Y" }}</p>
|
<p>by {{ deadline|naturalday:"M d, Y" }}</p>
|
||||||
<a href="/pledge/{{workid}}"><div class="read_itbutton pledge"><span>Support</span></div></a>
|
<a href="/pledge/{{workid}}"><div class="read_itbutton pledge"><span>Support</span></div></a>
|
||||||
|
|
||||||
{% else %}{% if status == 'INITIALIZED' %}
|
{% else %}{% if status == 'INITIALIZED' %}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
We thought you might like to know there are new comments for a book you have commented on.
|
{{ comment.user.username }} has commented on a book you also commented on, {{ comment.content_object.title }}, as follows.
|
||||||
|
|
||||||
{{ comment.user.username }} on {{ comment.content_object.title }}:
|
|
||||||
|
|
||||||
{{ comment.comment }}
|
{{ comment.comment }}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
{% load humanize %}You have modified a pledge that you had previously made to the campaign to unglue {{ transaction.campaign.work.title }}.
|
{% load humanize %}{% if up_or_down == 'canceled' %}You have canceled a pledge that you had previously made to the campaign to unglue {{ transaction.campaign.work.title }}.
|
||||||
|
|
||||||
|
Your canceled pledge
|
||||||
|
Amount: ${{ transaction.amount|intcomma }}
|
||||||
|
Premium: {% if transaction.premium %}{{ transaction.premium.description }}{% else %}None requested{% endif %}
|
||||||
|
{% else %}You have modified a pledge that you had previously made to the campaign to unglue {{ transaction.campaign.work.title }}.
|
||||||
|
|
||||||
Your new pledge summary
|
Your new pledge summary
|
||||||
Amount pledged: ${{ transaction.amount|intcomma }}
|
Amount pledged: ${{ transaction.amount|intcomma }}
|
||||||
Premium: {% if transaction.premium %}{{ transaction.premium.description }}{% else %}None requested{% endif %}
|
Premium: {% if transaction.premium %}{{ transaction.premium.description }}{% else %}None requested{% endif %}{% endif %}
|
||||||
|
|
||||||
{% if transaction.host|lower == 'amazon' %}{% if status == 'increased' %}
|
{% if transaction.host|lower == 'amazon' %}{% if up_or_down == 'increased' %}
|
||||||
You will also receive an email from Amazon confirming this.
|
You will also receive an email from Amazon confirming this.
|
||||||
{% else %}{% if status == 'decreased' %}
|
{% else %}{% if up_or_down == 'decreased' %}
|
||||||
Your Amazon Payments account may still show an authorization to Unglue.it for the entire amount of your earlier pledge, but never fear -- if the campaign succeeds, we'll only charge you ${{ transaction.amount|intcomma }}.
|
Your Amazon Payments account may still show an authorization to Unglue.it for the entire amount of your earlier pledge, but never fear -- if the campaign succeeds, we'll only charge you ${{ transaction.amount|intcomma }}.
|
||||||
{% endif %}{% endif %}{% else %}{% endif %}
|
{% endif %}{% endif %}{% else %}{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,19 @@
|
||||||
<a href="{% url work transaction.campaign.work.id %}"><img src="{{ transaction.campaign.work.cover_image_small }}" alt="cover image for {{ title }}" /></a>
|
<a href="{% url work transaction.campaign.work.id %}"><img src="{{ transaction.campaign.work.cover_image_small }}" alt="cover image for {{ title }}" /></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="comments_graphical">
|
<div class="comments_graphical">
|
||||||
Your pledge for the campaign to unglue {{ title }} has been modified.
|
Your pledge for the campaign to unglue {{ title }} has been {% if up_or_down == 'canceled'%}canceled{% else %}modified{% endif %}.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="comments_textual">
|
{% if up_or_down == 'canceled' %}<div class="comments_textual">
|
||||||
|
Your canceled pledge was as follows:<br />
|
||||||
|
Amount: ${{ transaction.amount|intcomma }}<br />
|
||||||
|
Premium: {% if transaction.premium %}{{ transaction.premium.description }}{% else %}None requested{% endif %}<br />
|
||||||
|
</div>{% else %}<div class="comments_textual">
|
||||||
Your new pledge is as follows:<br />
|
Your new pledge is as follows:<br />
|
||||||
Amount: ${{ transaction.amount|intcomma }}<br />
|
Amount: ${{ transaction.amount|intcomma }}<br />
|
||||||
Premium: {% if transaction.premium %}{{ transaction.premium.description }}{% else %}None requested{% endif %}<br />
|
Premium: {% if transaction.premium %}{{ transaction.premium.description }}{% else %}None requested{% endif %}<br />
|
||||||
Thank you for your continued support of {{ title }}.
|
Thank you for your continued support of {{ title }}.
|
||||||
</div>
|
</div>{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endwith %}
|
{% endwith %}
|
|
@ -1 +1 @@
|
||||||
Your pledge has been modified for {{ transaction.campaign.work.title}}
|
Your pledge has been {% if up_or_down == 'canceled'%}canceled{% else %}modified{% endif %} for {{ transaction.campaign.work.title}}
|
|
@ -1,6 +1,4 @@
|
||||||
We thought you might like to know there's a new comment for a book on your wishlist.
|
{{ comment.user.username }} has commented on a book on your wishlist, {{ comment.content_object.title }}, as follows.
|
||||||
|
|
||||||
{{ comment.user.username }} has commented on {{ comment.content_object.title }}:
|
|
||||||
|
|
||||||
{{ comment.comment }}
|
{{ comment.comment }}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
We thought you might like to know that Unglue.it staff or the book's rights holder have news about a book on your wishlist.
|
{{ comment.user.username }} has official news about a book on your wishlist, {{ comment.content_object.title }}.
|
||||||
|
|
||||||
{{ comment.user.username }} has commented on {{ comment.content_object.title }}:
|
|
||||||
|
|
||||||
{{ comment.comment }}
|
{{ comment.comment }}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,10 @@
|
||||||
|
|
||||||
<a id="latest"></a><h2>Latest Press</h2>
|
<a id="latest"></a><h2>Latest Press</h2>
|
||||||
<div class="pressarticles">
|
<div class="pressarticles">
|
||||||
|
<div>
|
||||||
|
<a href="hhttp://mashable.com/2012/06/14/unglueit/">Unglue.it Wants to Make a Creative Commons for Ebooks</a><br />
|
||||||
|
Mashable - June 14, 2012
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="http://www.huffingtonpost.com/2012/05/21/unglueit-free-ebooks-crowdfunding_n_1532644.html">Unglue.it Makes Free EBooks Through A Unique Crowdfunding Website</a><br />
|
<a href="http://www.huffingtonpost.com/2012/05/21/unglueit-free-ebooks-crowdfunding_n_1532644.html">Unglue.it Makes Free EBooks Through A Unique Crowdfunding Website</a><br />
|
||||||
Huffington Post - May 21, 2012
|
Huffington Post - May 21, 2012
|
||||||
|
@ -34,10 +38,6 @@
|
||||||
<a href="http://boingboing.net/2012/05/18/raising-money-to-free-classic.html">Raising money to free classic volume on Africa's oral literature</a><br />
|
<a href="http://boingboing.net/2012/05/18/raising-money-to-free-classic.html">Raising money to free classic volume on Africa's oral literature</a><br />
|
||||||
Boing Boing - May 18, 2012<br />
|
Boing Boing - May 18, 2012<br />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<a href="http://lj.libraryjournal.com/2012/05/publishing/ebook-crowdfunding-platform-unglue-it-launched/">Ebook Crowdfunding Platform Unglue.it Launched</a><br />
|
|
||||||
Library Journal - May 17, 2012
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a id="overview"></a><h2>Overview</h2>
|
<a id="overview"></a><h2>Overview</h2>
|
||||||
|
@ -73,6 +73,14 @@ Creative Commons offers a variety of other licenses, many of them with even less
|
||||||
</dl>
|
</dl>
|
||||||
<a id="press"></a><h2>Press Coverage</h2>
|
<a id="press"></a><h2>Press Coverage</h2>
|
||||||
<div class="pressarticles">
|
<div class="pressarticles">
|
||||||
|
<div>
|
||||||
|
<a href="hhttp://mashable.com/2012/06/14/unglueit/">Unglue.it Wants to Make a Creative Commons for Ebooks</a><br />
|
||||||
|
Mashable - June 14, 2012
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="http://goodereader.com/blog/electronic-readers/buzzwords-from-bookexpo/">Buzzwords from BookExpo</a><br />
|
||||||
|
Good EReader - June 07, 2012
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="http://www.huffingtonpost.com/2012/05/21/unglueit-free-ebooks-crowdfunding_n_1532644.html">Unglue.it Makes Free EBooks Through A Unique Crowdfunding Website</a><br />
|
<a href="http://www.huffingtonpost.com/2012/05/21/unglueit-free-ebooks-crowdfunding_n_1532644.html">Unglue.it Makes Free EBooks Through A Unique Crowdfunding Website</a><br />
|
||||||
Huffington Post - May 21, 2012
|
Huffington Post - May 21, 2012
|
||||||
|
@ -254,6 +262,11 @@ Creative Commons offers a variety of other licenses, many of them with even less
|
||||||
</div>
|
</div>
|
||||||
<a id="video"></a><h2>Video</h2>
|
<a id="video"></a><h2>Video</h2>
|
||||||
<div class="pressvideos">
|
<div class="pressvideos">
|
||||||
|
<div>
|
||||||
|
<iframe width="480" height="270" src="https://www.youtube-nocookie.com/embed/HxjTW4OBouo?rel=0" frameborder="0" allowfullscreen></iframe><br />
|
||||||
|
<I>June 2012</I><br />
|
||||||
|
Eric Hellman at Book Expo America.
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="mediaborder">
|
<div class="mediaborder">
|
||||||
<object width="480" height="270"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="https://secure.vimeo.com/moogaloop.swf?clip_id=39352026&server=secure.vimeo.com&show_title=1&show_byline=0&show_portrait=0&color=00adef&fullscreen=1&autoplay=0&loop=0" /><embed src="https://secure.vimeo.com/moogaloop.swf?clip_id=39352026&server=secure.vimeo.com&show_title=1&show_byline=0&show_portrait=0&color=00adef&fullscreen=1&autoplay=0&loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="480" height="270"></embed></object></div><br />
|
<object width="480" height="270"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="https://secure.vimeo.com/moogaloop.swf?clip_id=39352026&server=secure.vimeo.com&show_title=1&show_byline=0&show_portrait=0&color=00adef&fullscreen=1&autoplay=0&loop=0" /><embed src="https://secure.vimeo.com/moogaloop.swf?clip_id=39352026&server=secure.vimeo.com&show_title=1&show_byline=0&show_portrait=0&color=00adef&fullscreen=1&autoplay=0&loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="480" height="270"></embed></object></div><br />
|
||||||
|
|
|
@ -139,13 +139,23 @@ def work(request, work_id, action='display'):
|
||||||
|
|
||||||
countdown = ""
|
countdown = ""
|
||||||
if work.last_campaign_status() == 'ACTIVE':
|
if work.last_campaign_status() == 'ACTIVE':
|
||||||
|
from math import ceil
|
||||||
time_remaining = campaign.deadline - now()
|
time_remaining = campaign.deadline - now()
|
||||||
|
|
||||||
|
'''
|
||||||
|
we want to round up on all of these; if it's the 3rd and the
|
||||||
|
campaign ends the 8th, users expect to see 5 days remaining,
|
||||||
|
not 4 (as an artifact of 4 days 11 hours or whatever)
|
||||||
|
time_remaining.whatever is an int, so just adding 1 will do
|
||||||
|
that for us (except in the case where .days exists and both other
|
||||||
|
fields are 0, which is unlikely enough I'm not defending against it)
|
||||||
|
'''
|
||||||
if time_remaining.days:
|
if time_remaining.days:
|
||||||
countdown = "in %s days" % time_remaining.days
|
countdown = "in %s days" % str(time_remaining.days + 1)
|
||||||
elif time_remaining.seconds > 3600:
|
elif time_remaining.seconds > 3600:
|
||||||
countdown = "in %s hours" % time_remaining.seconds/3600
|
countdown = "in %s hours" % str(time_remaining.seconds/3600 + 1)
|
||||||
elif time_remaining.seconds > 60:
|
elif time_remaining.seconds > 60:
|
||||||
countdown = "in %s minutes" % time_remaining.seconds/60
|
countdown = "in %s minutes" % str(time_remaining.seconds/60 + 1)
|
||||||
else:
|
else:
|
||||||
countdown = "right now"
|
countdown = "right now"
|
||||||
if action == 'preview':
|
if action == 'preview':
|
||||||
|
@ -772,8 +782,6 @@ class PledgeModifyView(FormView):
|
||||||
elif status and url is None:
|
elif status and url is None:
|
||||||
# let's use the pledge_complete template for now and maybe look into customizing it.
|
# let's use the pledge_complete template for now and maybe look into customizing it.
|
||||||
return HttpResponseRedirect("{0}?tid={1}".format(reverse('pledge_complete'), transaction.id))
|
return HttpResponseRedirect("{0}?tid={1}".format(reverse('pledge_complete'), transaction.id))
|
||||||
from regluit.payment.signals import pledge_modified
|
|
||||||
pledge_modified.send(sender=self, transaction=transaction, status="increased")
|
|
||||||
else:
|
else:
|
||||||
return HttpResponse("No modification made")
|
return HttpResponse("No modification made")
|
||||||
|
|
||||||
|
@ -948,6 +956,11 @@ class PledgeCancelView(FormView):
|
||||||
# We might want to remove this in a production system
|
# We might want to remove this in a production system
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
update_status = p.update_preapproval(transaction)
|
update_status = p.update_preapproval(transaction)
|
||||||
|
# send a notice out that the transaction has been canceled -- leverage the pledge_modify notice for now
|
||||||
|
# BUGBUG: should have a pledge cancel notice actually since I think it's different
|
||||||
|
from regluit.payment.signals import pledge_modified
|
||||||
|
pledge_modified.send(sender=self, transaction=transaction, up_or_down="canceled")
|
||||||
|
logger.info("pledge_modified notice for cancellation: sender {0}, transaction {1}".format(self, transaction))
|
||||||
return HttpResponseRedirect(reverse('work', kwargs={'work_id': campaign.work.id}))
|
return HttpResponseRedirect(reverse('work', kwargs={'work_id': campaign.work.id}))
|
||||||
else:
|
else:
|
||||||
logger.error("Attempt to cancel transaction id {0} failed".format(transaction.id))
|
logger.error("Attempt to cancel transaction id {0} failed".format(transaction.id))
|
||||||
|
|
|
@ -50,7 +50,6 @@ AMAZON_OPERATION_TYPE_REFUND = 'REFUND'
|
||||||
AMAZON_OPERATION_TYPE_CANCEL = 'CANCEL'
|
AMAZON_OPERATION_TYPE_CANCEL = 'CANCEL'
|
||||||
|
|
||||||
# load FPS_ACCESS_KEY and FPS_SECRET_KEY from the database if possible
|
# load FPS_ACCESS_KEY and FPS_SECRET_KEY from the database if possible
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from regluit.core.models import Key
|
from regluit.core.models import Key
|
||||||
FPS_ACCESS_KEY = Key.objects.get(name="FPS_ACCESS_KEY").value
|
FPS_ACCESS_KEY = Key.objects.get(name="FPS_ACCESS_KEY").value
|
||||||
|
@ -210,6 +209,7 @@ def amazonPaymentReturn(request):
|
||||||
approves a preapproval or a pledge. This URL is set via the PAY api.
|
approves a preapproval or a pledge. This URL is set via the PAY api.
|
||||||
'''
|
'''
|
||||||
try:
|
try:
|
||||||
|
transaction = None
|
||||||
|
|
||||||
# pick up all get and post parameters and display
|
# pick up all get and post parameters and display
|
||||||
output = "payment complete"
|
output = "payment complete"
|
||||||
|
@ -279,7 +279,7 @@ def amazonPaymentReturn(request):
|
||||||
# We may never see an IPN, set the status here
|
# We may never see an IPN, set the status here
|
||||||
logging.error("Amazon payment authorization failed: ")
|
logging.error("Amazon payment authorization failed: ")
|
||||||
logging.error(request.GET)
|
logging.error(request.GET)
|
||||||
transaction.status = AMAZON_STATUS_FAILURE
|
transaction.status = TRANSACTION_STATUS_ERROR
|
||||||
|
|
||||||
|
|
||||||
elif transaction.type == PAYMENT_TYPE_AUTHORIZATION:
|
elif transaction.type == PAYMENT_TYPE_AUTHORIZATION:
|
||||||
|
@ -295,6 +295,14 @@ def amazonPaymentReturn(request):
|
||||||
transaction.status = TRANSACTION_STATUS_ACTIVE
|
transaction.status = TRANSACTION_STATUS_ACTIVE
|
||||||
transaction.approved = True
|
transaction.approved = True
|
||||||
transaction.pay_key = token
|
transaction.pay_key = token
|
||||||
|
transaction.save()
|
||||||
|
|
||||||
|
print "Calling CANCEL RELATED"
|
||||||
|
|
||||||
|
# clear out any other active transactions for this user and this campaign
|
||||||
|
from regluit.payment.manager import PaymentManager
|
||||||
|
p = PaymentManager()
|
||||||
|
p.cancel_related_transaction(transaction, status=TRANSACTION_STATUS_ACTIVE, campaign=transaction.campaign)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# We may never see an IPN, set the status here
|
# We may never see an IPN, set the status here
|
||||||
|
@ -307,24 +315,48 @@ def amazonPaymentReturn(request):
|
||||||
info = str(request.GET),
|
info = str(request.GET),
|
||||||
status = status,
|
status = status,
|
||||||
transaction=transaction)
|
transaction=transaction)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Corrupt transaciton, unknown type
|
||||||
|
transaction.status = TRANSACTION_STATUS_ERROR
|
||||||
|
|
||||||
transaction.save()
|
transaction.save()
|
||||||
|
|
||||||
# Redirect to our pledge success URL
|
if transaction.status == TRANSACTION_STATUS_ERROR:
|
||||||
return_path = "{0}?{1}".format(reverse('pledge_complete'),
|
# We failed, redirect to a page to allow the user to try again
|
||||||
urllib.urlencode({'tid':transaction.id}))
|
return_path = "{0}?{1}".format(reverse('pledge_nevermind'),
|
||||||
return_url = urlparse.urljoin(settings.BASE_URL, return_path)
|
urllib.urlencode({'tid':transaction.id}))
|
||||||
return HttpResponseRedirect(return_url)
|
return_url = urlparse.urljoin(settings.BASE_URL, return_path)
|
||||||
|
return HttpResponseRedirect(return_url)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Not a failure, exact status will be updated by IPN
|
||||||
|
# Redirect to our pledge success URL
|
||||||
|
return_path = "{0}?{1}".format(reverse('pledge_complete'),
|
||||||
|
urllib.urlencode({'tid':transaction.id}))
|
||||||
|
return_url = urlparse.urljoin(settings.BASE_URL, return_path)
|
||||||
|
return HttpResponseRedirect(return_url)
|
||||||
|
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
logging.error("Amazon co-branded return-url FAILED with exception:")
|
logging.error("Amazon co-branded return-url FAILED with exception:")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
# BUGBUG: check to see whether status is AMAZON_STATUS_ADBANDONED
|
|
||||||
# if so, ultimately figure out the campaign whose transaction is being canceled out.
|
if transaction:
|
||||||
# for the moment, return the user to BASE_URL
|
|
||||||
|
|
||||||
if request.REQUEST.get("status") == AMAZON_STATUS_ADBANDONED:
|
# We failed, redirect to a page to allow the user to try again
|
||||||
|
return_path = "{0}?{1}".format(reverse('pledge_nevermind'),
|
||||||
|
urllib.urlencode({'tid':transaction.id}))
|
||||||
|
return_url = urlparse.urljoin(settings.BASE_URL, return_path)
|
||||||
|
return HttpResponseRedirect(return_url)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
#
|
||||||
|
# If we are here, amazon did not give us a caller reference, so we don't know what transaction was cancelled.
|
||||||
|
# Some kind of cleanup is required. This can happen if there is an error in the amazon API or if the user clicks
|
||||||
|
# the cancel button. If the case where the user closes the co-branded window or hits the back button, we will never arrive here.
|
||||||
|
#
|
||||||
return HttpResponseRedirect(settings.BASE_URL)
|
return HttpResponseRedirect(settings.BASE_URL)
|
||||||
|
|
||||||
class AmazonRequest:
|
class AmazonRequest:
|
||||||
|
|
|
@ -194,19 +194,39 @@ class PaymentManager( object ):
|
||||||
logger.info(preapproval_transactions)
|
logger.info(preapproval_transactions)
|
||||||
|
|
||||||
transactions = payment_transactions | preapproval_transactions
|
transactions = payment_transactions | preapproval_transactions
|
||||||
|
|
||||||
|
|
||||||
for t in transactions:
|
for t in transactions:
|
||||||
|
|
||||||
|
# deal with preapprovals
|
||||||
if t.date_payment is None:
|
if t.date_payment is None:
|
||||||
preapproval_status = self.update_preapproval(t)
|
preapproval_status = self.update_preapproval(t)
|
||||||
logger.info("transaction: {0}, preapproval_status: {1}".format(t, preapproval_status))
|
logger.info("transaction: {0}, preapproval_status: {1}".format(t, preapproval_status))
|
||||||
if not set(['status', 'currency', 'amount', 'approved']).isdisjoint(set(preapproval_status.keys())):
|
if not set(['status', 'currency', 'amount', 'approved']).isdisjoint(set(preapproval_status.keys())):
|
||||||
status["preapprovals"].append(preapproval_status)
|
status["preapprovals"].append(preapproval_status)
|
||||||
|
# update payments
|
||||||
else:
|
else:
|
||||||
payment_status = self.update_payment(t)
|
payment_status = self.update_payment(t)
|
||||||
if not set(["status", "receivers"]).isdisjoint(payment_status.keys()):
|
if not set(["status", "receivers"]).isdisjoint(payment_status.keys()):
|
||||||
status["payments"].append(payment_status)
|
status["payments"].append(payment_status)
|
||||||
|
|
||||||
|
# Clear out older, duplicate preapproval transactions
|
||||||
|
cleared_list = []
|
||||||
|
for p in transactions:
|
||||||
|
|
||||||
|
# pick out only the preapprovals
|
||||||
|
if p.date_payment is None and p.type == PAYMENT_TYPE_AUTHORIZATION and p.status == TRANSACTION_STATUS_ACTIVE and p not in cleared_list:
|
||||||
|
|
||||||
|
# keep only the newest transaction for this user and campaign
|
||||||
|
user_transactions_for_campaign = Transaction.objects.filter(user=p.user, status=TRANSACTION_STATUS_ACTIVE, campaign=p.campaign).order_by('-date_authorized')
|
||||||
|
|
||||||
|
if len(user_transactions_for_campaign) > 1:
|
||||||
|
logger.info("Found %d active transactions for campaign" % len(user_transactions_for_campaign))
|
||||||
|
self.cancel_related_transaction(user_transactions_for_campaign[0], status=TRANSACTION_STATUS_ACTIVE, campaign=transactions[0].campaign)
|
||||||
|
|
||||||
|
cleared_list.extend(user_transactions_for_campaign)
|
||||||
|
|
||||||
|
# Note, we may need to call checkstatus again here
|
||||||
|
|
||||||
return status
|
return status
|
||||||
|
|
||||||
|
@ -629,10 +649,14 @@ class PaymentManager( object ):
|
||||||
# that for whatever reason fail. will need other housekeeping to handle those.
|
# that for whatever reason fail. will need other housekeeping to handle those.
|
||||||
# sadly this point is not yet late enough in the process -- needs to be moved
|
# sadly this point is not yet late enough in the process -- needs to be moved
|
||||||
# until after we are certain.
|
# until after we are certain.
|
||||||
if modification:
|
|
||||||
pledge_modified.send(sender=self, transaction=t, up_or_down="increased")
|
if not modification:
|
||||||
else:
|
# BUGBUG:
|
||||||
|
# send the notice here for now
|
||||||
|
# this is actually premature since we're only about to send the user off to the payment system to
|
||||||
|
# authorize a charge
|
||||||
pledge_created.send(sender=self, transaction=t)
|
pledge_created.send(sender=self, transaction=t)
|
||||||
|
|
||||||
return t, url
|
return t, url
|
||||||
|
|
||||||
|
|
||||||
|
@ -642,6 +666,48 @@ class PaymentManager( object ):
|
||||||
logger.info("Authorize Error: " + p.error_string())
|
logger.info("Authorize Error: " + p.error_string())
|
||||||
return t, None
|
return t, None
|
||||||
|
|
||||||
|
def cancel_related_transaction(self, transaction, status=TRANSACTION_STATUS_ACTIVE, campaign=None):
|
||||||
|
'''
|
||||||
|
Cancels any other similar status transactions for the same campaign. Used with modify code
|
||||||
|
|
||||||
|
Returns the number of transactions successfully canceled
|
||||||
|
'''
|
||||||
|
|
||||||
|
related_transactions = Transaction.objects.filter(status=status, user=transaction.user)
|
||||||
|
|
||||||
|
if len(related_transactions) == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if campaign:
|
||||||
|
related_transactions = related_transactions.filter(campaign=campaign)
|
||||||
|
|
||||||
|
canceled = 0
|
||||||
|
|
||||||
|
for t in related_transactions:
|
||||||
|
|
||||||
|
if t.id == transaction.id:
|
||||||
|
# keep our transaction
|
||||||
|
continue
|
||||||
|
|
||||||
|
if self.cancel_transaction(t):
|
||||||
|
canceled = canceled + 1
|
||||||
|
# send notice about modification of transaction
|
||||||
|
if transaction.amount > t.amount:
|
||||||
|
# this should be the only one that happens
|
||||||
|
up_or_down = "increased"
|
||||||
|
elif transaction.amount < t.amount:
|
||||||
|
# we shouldn't expect any case in which this happens
|
||||||
|
up_or_down = "decreased"
|
||||||
|
else:
|
||||||
|
# we shouldn't expect any case in which this happens
|
||||||
|
up_or_down = None
|
||||||
|
|
||||||
|
pledge_modified.send(sender=self, transaction=transaction, up_or_down=up_or_down)
|
||||||
|
else:
|
||||||
|
logger.error("Failed to cancel transaction {0} for related transaction {1} ".format(t, transaction))
|
||||||
|
|
||||||
|
return canceled
|
||||||
|
|
||||||
def modify_transaction(self, transaction, amount, expiry=None, anonymous=None, premium=None,
|
def modify_transaction(self, transaction, amount, expiry=None, anonymous=None, premium=None,
|
||||||
return_url=None, nevermind_url=None,
|
return_url=None, nevermind_url=None,
|
||||||
paymentReason=None):
|
paymentReason=None):
|
||||||
|
@ -701,10 +767,15 @@ class PaymentManager( object ):
|
||||||
if t and url:
|
if t and url:
|
||||||
# Need to re-direct to approve the transaction
|
# Need to re-direct to approve the transaction
|
||||||
logger.info("New authorization needed, redirection to url %s" % url)
|
logger.info("New authorization needed, redirection to url %s" % url)
|
||||||
self.cancel_transaction(transaction)
|
|
||||||
|
# Do not cancel the transaction here, wait until we get confirmation that the transaction is complete
|
||||||
|
# then cancel all other active transactions for this campaign
|
||||||
|
#self.cancel_transaction(transaction)
|
||||||
|
|
||||||
# while it would seem to make sense to send a pledge notification change here
|
# while it would seem to make sense to send a pledge notification change here
|
||||||
# if we do, we will also send notifications when we initiate but do not
|
# if we do, we will also send notifications when we initiate but do not
|
||||||
# successfully complete a pledge modification
|
# successfully complete a pledge modification
|
||||||
|
|
||||||
return True, url
|
return True, url
|
||||||
else:
|
else:
|
||||||
# a problem in authorize
|
# a problem in authorize
|
||||||
|
|
|
@ -316,9 +316,6 @@ ul.navigation li.active a {
|
||||||
.listview.icons .booklist-status-label {
|
.listview.icons .booklist-status-label {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.listview.icons .boolist-ebook span {
|
|
||||||
padding-bottom: 6px;
|
|
||||||
}
|
|
||||||
div#content-block-content {
|
div#content-block-content {
|
||||||
padding-bottom: 100px;
|
padding-bottom: 100px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,12 +251,6 @@ ul.navigation li a:hover, ul.navigation li.active a {
|
||||||
.booklist-status-label, {
|
.booklist-status-label, {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.boolist-ebook {
|
|
||||||
span {
|
|
||||||
padding-bottom: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div#content-block-content {
|
div#content-block-content {
|
||||||
|
|
Loading…
Reference in New Issue