pull/1/head
eric 2012-07-15 16:58:52 -04:00
commit cf3351d84b
6 changed files with 126 additions and 12 deletions

View File

@ -18,7 +18,10 @@ import regluit.core.isbn
from regluit.core.signals import successful_campaign, unsuccessful_campaign
import binascii
from regluit.payment.parameters import TRANSACTION_STATUS_ACTIVE
from regluit.payment.parameters import TRANSACTION_STATUS_ACTIVE, TRANSACTION_STATUS_COMPLETE, TRANSACTION_STATUS_CANCELED, TRANSACTION_STATUS_ERROR, TRANSACTION_STATUS_FAILED, TRANSACTION_STATUS_INCOMPLETE
from django.db.models import Q
class UnglueitError(RuntimeError):
pass
@ -323,7 +326,26 @@ class Campaign(models.Model):
def supporters_count(self):
# avoid transmitting the whole list if you don't need to; let the db do the count.
return self.transactions().filter(status=TRANSACTION_STATUS_ACTIVE).values_list('user', flat=True).distinct().count()
def transaction_to_recharge(self, user):
"""given a user, return the transaction to be recharged if there is one -- None otherwise"""
# only if a campaign is SUCCESSFUL, we allow for recharged
if self.status == 'SUCCESSFUL':
if self.transaction_set.filter(Q(user=user) & (Q(status=TRANSACTION_STATUS_COMPLETE) | Q(status=TRANSACTION_STATUS_ACTIVE))).count():
# presence of an active or complete transaction means no transaction to recharge
return None
else:
transactions = self.transaction_set.filter(Q(user=user) & (Q(status=TRANSACTION_STATUS_ERROR) | Q(status=TRANSACTION_STATUS_FAILED)))
# assumption --that the first failed/errored transaction has the amount we need to recharge
if transactions.count():
return transactions[0]
else:
return None
else:
return None
def ungluers(self):
p = PaymentManager()
ungluers={"all":[],"supporters":[], "patrons":[], "bibliophiles":[]}
@ -804,7 +826,21 @@ class UserProfile(models.Model):
goodreads_auth_token = models.TextField(null=True, blank=True)
goodreads_auth_secret = models.TextField(null=True, blank=True)
goodreads_user_link = models.CharField(max_length=200, null=True, blank=True)
#class CampaignSurveyResponse(models.Model):
# # generic
# campaign = models.ForeignKey("Campaign", related_name="surveyresponse", null=False)
# user = models.OneToOneField(User, related_name='surveyresponse')
# transaction = models.ForeignKey("payment.Transaction", null=True)
# # for OLA only
# premium = models.ForeignKey("Premium", null=True)
# anonymous = models.BooleanField(null=False)
# # relevant to all campaigns since these arise from acknowledgement requirements from generic premiums
# name = models.CharField(max_length=140, blank=True)
# url = models.URLField(blank=True)
# tagline = models.CharField(max_length=140, blank=True)
# # do we need to collect address for Rupert or will he do that once he has emails?
# this was causing a circular import problem and we do not seem to be using
# anything from regluit.core.signals after this line
# from regluit.core import signals

4
fabfile.py vendored
View File

@ -87,7 +87,9 @@ def public_key_from_private_key():
def email_addresses():
"""list email addresses in unglue.it"""
with cd("/opt/regluit"):
run("""source ENV/bin/activate; echo "import django; print ' \\n'.join([u.email for u in django.contrib.auth.models.User.objects.all() ]); quit()" | django-admin.py shell_plus --settings=regluit.settings.me""")
run("""source ENV/bin/activate; echo "import django; print ' \\n'.join([u.email for u in django.contrib.auth.models.User.objects.all() ]); quit()" | django-admin.py shell_plus --settings=regluit.settings.me > /home/ubuntu/emails.txt""")
local("scp web1:/home/ubuntu/emails.txt .")
run("""rm /home/ubuntu/emails.txt""")
def selenium():
"""setting up selenium to run in the background on RY's laptop"""

View File

@ -85,7 +85,7 @@
</div>
<div class="launch_top">
The <a href="/work/81724/">first unglued book</a> is on the way! Please consider supporting our <a href="/campaigns/ending#2">three active campaigns</a>.
The <a href="/work/81724/">first unglued book</a> is on the way! Please consider supporting our <a href="/campaigns/ending#2">four active campaigns</a>.
</div>
{% block topsection %}{% endblock %}
{% block content %}{% endblock %}

View File

@ -7,7 +7,7 @@ from django.conf import settings
from regluit.core.feeds import SupporterWishlistFeed
from regluit.core.models import Campaign
from regluit.frontend.views import GoodreadsDisplayView, LibraryThingView, PledgeView, PledgeCompleteView, PledgeModifyView, PledgeCancelView, PledgeNeverMindView, FAQView
from regluit.frontend.views import GoodreadsDisplayView, LibraryThingView, PledgeView, PledgeCompleteView, PledgeModifyView, PledgeCancelView, PledgeNeverMindView, PledgeRechargeView, FAQView
from regluit.frontend.views import CampaignListView, DonateView, WorkListView, UngluedListView, InfoPageView
urlpatterns = patterns(
@ -55,6 +55,7 @@ urlpatterns = patterns(
url(r"^pledge/complete/$", login_required(PledgeCompleteView.as_view()), name="pledge_complete"),
url(r"^pledge/nevermind/$", login_required(PledgeNeverMindView.as_view()), name="pledge_nevermind"),
url(r"^pledge/modify/(?P<work_id>\d+)$", login_required(PledgeModifyView.as_view()), name="pledge_modify"),
url(r"^pledge/recharge/(?P<work_id>\d+)$", login_required(PledgeRechargeView.as_view()), name="pledge_recharge"),
url(r"^subjects/$", "subjects", name="subjects"),
url(r"^librarything/$", LibraryThingView.as_view(), name="librarything"),
url(r"^librarything/load/$","librarything_load", name="librarything_load"),

View File

@ -674,7 +674,8 @@ class PledgeView(FormView):
class PledgeModifyView(FormView):
"""
A view to handle request to change an existing pledge
"""
"""
template_name="pledge.html"
form_class = CampaignPledgeForm
embedded = False
@ -798,6 +799,58 @@ class PledgeModifyView(FormView):
return HttpResponse("No modification made")
class PledgeRechargeView(TemplateView):
"""
a view to allow for recharge of a transaction for failed transactions or ones with errors
"""
template_name="pledge_recharge.html"
def get_context_data(self, **kwargs):
context = super(PledgeRechargeView, self).get_context_data(**kwargs)
# the following should be true since PledgeModifyView.as_view is wrapped in login_required
assert self.request.user.is_authenticated()
user = self.request.user
work = get_object_or_404(models.Work, id=self.kwargs["work_id"])
campaign = work.last_campaign()
if campaign is None:
return Http404
transaction = campaign.transaction_to_recharge(user)
# calculate a URL to do a preapproval -- in the future, we may want to do a straight up payment
return_url = None
nevermind_url = None
if transaction is not None:
# the recipients of this authorization is not specified here but rather by the PaymentManager.
# set the expiry date based on the campaign deadline
expiry = campaign.deadline + timedelta( days=settings.PREAPPROVAL_PERIOD_AFTER_CAMPAIGN )
paymentReason = "Unglue.it Recharge for {0}".format(campaign.name)
p = PaymentManager(embedded=False)
t, url = p.authorize('USD', TARGET_TYPE_CAMPAIGN, transaction.amount, expiry=expiry, campaign=campaign, list=None, user=user,
return_url=return_url, nevermind_url=nevermind_url, anonymous=transaction.anonymous, premium=transaction.premium,
paymentReason=paymentReason)
logger.info("Recharge url: {0}".format(url))
else:
url = None
context.update({
'work':work,
'transaction':transaction,
'payment_processor':transaction.host if transaction is not None else None,
'recharge_url': url
})
return context
class PledgeCompleteView(TemplateView):
"""A callback for PayPal to tell unglue.it that a payment transaction has completed successfully.

View File

@ -220,14 +220,36 @@ def amazonPaymentReturn(request):
status = request.GET['status']
reference = request.GET['callerReference']
token = request.GET['tokenID']
# BUGUBG - Should we verify the signature here?
#
# validate the signature
uri = request.build_absolute_uri()
parsed_url = urlparse.urlparse(uri)
connection = FPSConnection(FPS_ACCESS_KEY, FPS_SECRET_KEY, host=settings.AMAZON_FPS_HOST)
# Check the validity of the IPN
resp = connection.verify_signature("%s://%s%s" %(parsed_url.scheme,
parsed_url.netloc,
parsed_url.path),
urllib.urlencode(request.GET))
if not resp[0].VerificationStatus == "Success":
# Error, ignore this
logging.error("amazonPaymentReturn cannot be verified with get data: ")
logging.error(request.GET)
return HttpResponseForbidden()
logging.debug("amazonPaymentReturn sig verified:")
logging.debug(request.GET)
# validation of signature ok
# Find the transaction by reference, there should only be one
# We will catch the exception if it does not exist
#
transaction = Transaction.objects.get(secret=reference)
try:
transaction = Transaction.objects.get(secret=reference)
except:
logging.info("transaction with secret {0}".format(reference))
return HttpResponseForbidden()
logging.info("Amazon Co-branded Return URL called for transaction id: %d" % transaction.id)
logging.info(request.GET)