Mercurial > public > sg101
view gpp/donations/views.py @ 265:1ba2c6bf6eb7
Closing #98. Animated GIFs were losing their transparency and animated properties when saved as avatars. Reworked the avatar save process to only run the avatar through PIL if it is too big. This preserves the original uploaded file if it is within the desired size settings. This may still mangle big animated gifs. If this becomes a problem, then maybe look into calling the PIL Image.resize() method directly. Moved the PIL image specific functions from bio.forms to a new module: core.image for better reusability in the future.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Fri, 24 Sep 2010 02:12:09 +0000 |
parents | a3b47d0f4df1 |
children | 767cedc7d12a |
line wrap: on
line source
""" Views for the donations application. """ import urllib2 import decimal import datetime from django.shortcuts import render_to_response from django.template import RequestContext from django.conf import settings from django.contrib.sites.models import Site from django.http import HttpResponse from django.http import HttpResponseServerError from django.contrib.auth.models import User from django.views.decorators.csrf import csrf_exempt from donations.models import Donation PP_DATE_FMT = '%H:%M:%S %b %d, %Y' def paypal_params(): """ This function returns a tuple where the 1st element is the Paypal URL and the 2nd element is the Paypal business email. This information depends on the setting DONATIONS_DEBUG. """ if settings.DONATIONS_DEBUG: form_action = 'https://www.sandbox.paypal.com/cgi-bin/webscr' business = settings.DONATIONS_BUSINESS_DEBUG else: form_action = 'https://www.paypal.com/cgi-bin/webscr' business = settings.DONATIONS_BUSINESS return form_action, business def index(request): gross, net, donations = Donation.objects.monthly_stats() current_site = Site.objects.get_current() form_action, business = paypal_params() return render_to_response('donations/index.html', { 'goal': settings.DONATIONS_GOAL, 'gross': gross, 'net': net, 'left': settings.DONATIONS_GOAL - net, 'donations': donations, 'form_action': form_action, 'business': business, 'anonymous': settings.DONATIONS_ANON_NAME, 'item_name': settings.DONATIONS_ITEM_NAME, 'item_number': settings.DONATIONS_ITEM_NUM, 'item_anon_number': settings.DONATIONS_ITEM_ANON_NUM, 'domain': current_site.domain, }, context_instance = RequestContext(request)) @csrf_exempt def ipn(request): """ This function is the IPN listener and handles the IPN POST from Paypal. The algorithm here roughly follows the outline described in chapter 2 of Paypal's IPNGuide.pdf "Implementing an IPN Listener". """ import logging # Log some info about this IPN event ip = request.META.get('REMOTE_ADDR', '?') parameters = request.POST.copy() logging.info('IPN from %s; post data: %s' % (ip, parameters.urlencode())) # Now we follow the instructions in chapter 2 of the Paypal IPNGuide.pdf. # Create a request that contains exactly the same IPN variables and values in # the same order, preceded with cmd=_notify-validate parameters['cmd']='_notify-validate' # Post the request back to Paypal (either to the sandbox or the real deal). req = urllib2.Request(paypal_params()[0], parameters.urlencode()) req.add_header("Content-type", "application/x-www-form-urlencoded") response = urllib2.urlopen(req) # Wait for the response from Paypal, which should be either VERIFIED or INVALID. status = response.read() if status != 'VERIFIED': logging.warning('IPN: Payapl did not verify; status was %s' % status) return HttpResponse() # Response was VERIFIED; act on this if it is a Completed donation, # otherwise don't handle it (we are just a donations application. Here # is where we could be expanded to be a more general payment processor). payment_status = parameters.get('payment_status') if payment_status != 'Completed': logging.info('IPN: payment_status is %s; we are done.' % payment_status) return HttpResponse() # Is this a donation to the site? item_number = parameters.get('item_number') if item_number == settings.DONATIONS_ITEM_NUM or \ item_number == settings.DONATIONS_ITEM_ANON_NUM: process_donation(item_number, parameters) else: logging.info('IPN: not a donation; done.') return HttpResponse() def process_donation(item_number, params): """ A few validity and duplicate checks are made on the donation params. If everything is ok, construct a donation object from the parameters and store it in the database. """ import logging # Has this transaction been processed before? txn_id = params.get('txn_id') if txn_id is None: logging.error('IPN: missing txn_id') return try: donation = Donation.objects.get(txn_id__exact=txn_id) except Donation.DoesNotExist: pass else: logging.warning('IPN: duplicate txn_id') return # no exception, this is a duplicate # Is the email address ours? business = params.get('business') if business != paypal_params()[1]: logging.warning('IPN: invalid business: %s' % business) return # is this a payment received? txn_type = params.get('txn_type') if txn_type != 'web_accept': logging.warning('IPN: invalid txn_type: %s' % txn_type) return # Looks like a donation, save it to the database. # Determine which user this came from, if any. # The username is stored in the custom field if the user was logged in when # the donation was made. user = None if 'custom' in params and params['custom']: try: user = User.objects.get(username__exact=params['custom']) except User.DoesNotExist: pass is_anonymous = item_number == settings.DONATIONS_ITEM_ANON_NUM test_ipn = params.get('test_ipn') == '1' first_name = params.get('first_name', '') last_name = params.get('last_name', '') payer_email = params.get('payer_email', '') payer_id = params.get('payer_id', '') memo = params.get('memo', '') payer_status = params.get('payer_status', '') try: mc_gross = decimal.Decimal(params['mc_gross']) mc_fee = decimal.Decimal(params['mc_fee']) except KeyError, decimal.InvalidOperation: logging.error('IPN: invalid/missing mc_gross or mc_fee') return payment_date = params.get('payment_date') if payment_date is None: logging.error('IPN: missing payment_date') return # strip off the timezone payment_date = payment_date[:-4] try: payment_date = datetime.datetime.strptime(payment_date, PP_DATE_FMT) except ValueError: logging.error('IPN: invalid payment_date "%s"' % params['payment_date']) return try: donation = Donation( user=user, is_anonymous=is_anonymous, test_ipn=test_ipn, txn_id=txn_id, txn_type=txn_type, first_name=first_name, last_name=last_name, payer_email=payer_email, payer_id=payer_id, memo=memo, payer_status=payer_status, mc_gross=mc_gross, mc_fee=mc_fee, payment_date=payment_date) except: logging.exception('IPN: exception during donation creation') else: donation.save() logging.info('IPN: donation saved')