def automail_prize_contributors(event, prizes, mailTemplate, domain=settings.DOMAIN, sender=None, replyTo=None, verbosity=0, dry_run=False):
    sender, replyTo = event_sender_replyto_defaults(event, sender, replyTo)
    
    handlerDict = {}
    for prize in prizes:
        if prize.handler:
            prizeList = handlerDict.setdefault(prize.handler, [])
            prizeList.append(prize)
    for handler, prizeList in handlerDict.iteritems():
        denied = list(filter(lambda prize: prize.state == 'DENIED', prizeList))
        formatContext = {
            'user_index_url': domain + reverse('user_index'),
            'event': event,
            'handler': handler,
            'accepted_prizes': list(filter(lambda prize: prize.state == 'ACCEPTED', prizeList)),
            'denied_prizes': list(filter(lambda prize: prize.state == 'DENIED', prizeList)),
            'reply_address': replyTo,
            'event': event,
        }
        if not dry_run:
            post_office.mail.send(recipients=[handler.email], sender=sender,
                template=mailTemplate, context=formatContext, headers={'Reply-to': replyTo})
        message = 'Mailed prize handler {0} for prizes {1}'.format(handler.id, list(map(lambda p: p.id, prizeList)))
        if verbosity > 0:
            print(message)
        if not dry_run:
            viewutil.tracker_log('prize', message, event)
            for prize in prizeList:
                prize.acceptemailsent = True
                prize.save()
def automail_winner_accepted_prize(event, prizeWinners, mailTemplate, domain=settings.DOMAIN, sender=None, replyTo=None, verbosity=0, dry_run=False):
    sender, replyTo = event_sender_replyto_defaults(event, sender, replyTo)
    
    handlerDict = {}
    for prizeWinner in prizeWinners:
        if prizeWinner.prize.handler:
            prizeList = handlerDict.setdefault(prizeWinner.prize.handler, [])
            prizeList.append(prizeWinner)
    for handler, prizeList in handlerDict.iteritems():
        formatContext = {
            'user_index_url': domain + reverse('user_index'),
            'prize_wins': prizeList,
            'prize_count': len(prizeList),
            'handler': handler,
            'event': event,
            'reply_address': replyTo,
        }
        if not dry_run:
            post_office.mail.send(recipients=[handler.email], sender=sender,
                template=mailTemplate, context=formatContext, headers={'Reply-to': replyTo})
        message = 'Mailed handler {0} for prize accepts {1}'.format(handler.id, list(map(lambda pw: pw.id, prizeList)))
        if verbosity > 0:
            print(message)
        if not dry_run:
            viewutil.tracker_log('prize', message, event)
            for prizeWinner in prizeList:
                prizeWinner.acceptemailsentcount = prizeWinner.acceptcount
                prizeWinner.save()
def automail_shipping_email_notifications(event, prizeWinners, mailTemplate, domain=settings.DOMAIN, sender=None, replyTo=None, verbosity=0, dry_run=False):
    sender, replyTo = event_sender_replyto_defaults(event, sender, replyTo)
    
    winnerDict = {}
    for prizeWinner in prizeWinners:
        prizeList = winnerDict.setdefault(prizeWinner.winner, [])
        prizeList.append(prizeWinner)
    for winner, prizeList in winnerDict.iteritems():
        formatContext = {
            'prize_wins': prizeList,
            'prize_count': len(prizeList),
            'winner': winner,
            'event': event,
            'reply_address': replyTo,
        }
        if not dry_run:
            post_office.mail.send(recipients=[winner.email], sender=sender,
                template=mailTemplate, context=formatContext, headers={'Reply-to': replyTo})
        message = 'Mailed donor {0} for prizes shipped {1}'.format(winner.id, list(map(lambda pw: pw.id, prizeList)))
        if verbosity > 0:
            print(message)
        if not dry_run:
            viewutil.tracker_log('prize', message, event)
            for prizeWinner in prizeList:
                prizeWinner.shippingemailsent = True
                prizeWinner.save()
def post_donation_to_postbacks(donation):
    event_donations = filters.run_model_query('donation',
                                              {'event': donation.event.id})
    total = event_donations.aggregate(amount=Sum('amount'))['amount']

    data = {
        'id': donation.id,
        'timereceived': str(donation.timereceived),
        'comment': donation.comment,
        'amount': donation.amount,
        'donor__visibility': donation.donor.visibility,
        'donor__visiblename': donation.donor.visible_name(),
        'new_total': total,
        'domain': donation.domain
    }

    # XXX: django/urllib2 throws UnicodeDecideError when payloads contain
    # unicode codepoints:
    #   UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 292: ordinal not in range(128)
    try:
        data_json = json.dumps(
            data, ensure_ascii=False, cls=serializers.json.DjangoJSONEncoder).encode('utf-8')

        postbacks = models.PostbackURL.objects.filter(event=donation.event)
        for postback in postbacks:
            opener = urllib2.build_opener()
            req = urllib2.Request(postback.url, data_json,
                                  headers={'Content-Type': 'application/json; charset=utf-8'})
            response = opener.open(req, timeout=5)
    except Exception as e:
        viewutil.tracker_log(
            'postback_url', traceback.format_exc(), event=donation.event)
Example #5
0
def ipn(request):
    ipnObj = None

    if request.method == 'GET' or len(request.POST) == 0:
        return views_common.tracker_response(request, "tracker/badobject.html", {})

    try:
        ipnObj = paypalutil.create_ipn(request)
        ipnObj.save()

        donation = paypalutil.initialize_paypal_donation(ipnObj)
        donation.save()

        if donation.transactionstate == 'PENDING':
            reasonExplanation, ourFault = paypalutil.get_pending_reason_details(
                ipnObj.pending_reason)
            if donation.event.pendingdonationemailtemplate:
                formatContext = {
                    'event': donation.event,
                    'donation': donation,
                    'donor': donation.donor,
                    'pending_reason': ipnObj.pending_reason,
                    'reason_info': reasonExplanation if not ourFault else '',
                }
                post_office.mail.send(recipients=[donation.donor.email], sender=donation.event.donationemailsender,
                                      template=donation.event.pendingdonationemailtemplate, context=formatContext)
            # some pending reasons can be a problem with the receiver account, we should keep track of them
            if ourFault:
                paypalutil.log_ipn(ipnObj, 'Unhandled pending error')
        elif donation.transactionstate == 'COMPLETED':
            if donation.event.donationemailtemplate != None:
                formatContext = {
                    'donation': donation,
                    'donor': donation.donor,
                    'event': donation.event,
                    'prizes': viewutil.get_donation_prize_info(donation),
                }
                post_office.mail.send(recipients=[donation.donor.email], sender=donation.event.donationemailsender,
                                      template=donation.event.donationemailtemplate, context=formatContext)
            eventutil.post_donation_to_postbacks(donation)

        elif donation.transactionstate == 'CANCELLED':
            # eventually we may want to send out e-mail for some of the possible cases
            # such as payment reversal due to double-transactions (this has happened before)
            paypalutil.log_ipn(ipnObj, 'Cancelled/reversed payment')

    except Exception as inst:
        # just to make sure we have a record of it somewhere
        print("ERROR IN IPN RESPONSE, FIX IT")
        if ipnObj:
            paypalutil.log_ipn(ipnObj, "{0} \n {1}. POST data : {2}".format(
                inst, traceback.format_exc(inst), request.POST))
        else:
            viewutil.tracker_log('paypal', 'IPN creation failed: {0} \n {1}. POST data : {2}'.format(
                inst, traceback.format_exc(inst), request.POST))
    return HttpResponse("OKAY")
Example #6
0
def automail_prize_winners(event,
                           prizeWinners,
                           mailTemplate,
                           sender=None,
                           replyTo=None,
                           domain=settings.DOMAIN,
                           verbosity=0,
                           dry_run=False):
    sender, replyTo = event_sender_replyto_defaults(event, sender, replyTo)

    winnerDict = {}
    for prizeWinner in prizeWinners:
        if prizeWinner.winner.id in winnerDict.keys():
            winList = winnerDict[prizeWinner.winner.id]
        else:
            winList = []
            winnerDict[prizeWinner.winner.id] = winList
        winList.append(prizeWinner)
    for winnerk, prizesWon in winnerDict.iteritems():
        winner = prizesWon[0].winner
        prizesList = []
        minAcceptDeadline = min(
            itertools.chain(
                filter(lambda x: x != None,
                       map(lambda pw: pw.accept_deadline_date(), prizesWon)),
                [datetime.date.max]))

        for prizeWon in prizesWon:
            prizesList.append(prizeWon.prize)
        formatContext = {
            'event': event,
            'winner': winner,
            'prize_wins': prizesWon,
            'multi': len(prizesWon) > 1,
            'prize_count': len(prizesWon),
            'reply_address': replyTo,
            'accept_deadline': minAcceptDeadline,
        }

        if not dry_run:
            post_office.mail.send(recipients=[winner.email],
                                  sender=sender,
                                  template=mailTemplate,
                                  context=formatContext,
                                  headers={'Reply-to': replyTo})

        message = 'Mailed donor {0} for prize wins {1}'.format(
            winner.id, list(map(lambda pw: pw.id, prizesWon)))

        if verbosity > 0:
            print(message)
        if not dry_run:
            viewutil.tracker_log('prize', message, event)
            for prizeWon in prizesWon:
                prizeWon.emailsent = True
                prizeWon.save()
def ipn(request):
    ipnObj = None

    if request.method == 'GET' or len(request.POST) == 0:
        return views_common.tracker_response(request, "tracker/badobject.html", {})

    try:
        ipnObj = paypalutil.create_ipn(request)
        ipnObj.save()

        donation = paypalutil.initialize_paypal_donation(ipnObj)
        donation.save()

        if donation.transactionstate == 'PENDING':
            reasonExplanation, ourFault = paypalutil.get_pending_reason_details(
                ipnObj.pending_reason)
            if donation.event.pendingdonationemailtemplate:
                formatContext = {
                    'event': donation.event,
                    'donation': donation,
                    'donor': donation.donor,
                    'pending_reason': ipnObj.pending_reason,
                    'reason_info': reasonExplanation if not ourFault else '',
                }
                post_office.mail.send(recipients=[donation.donor.email], sender=donation.event.donationemailsender,
                                      template=donation.event.pendingdonationemailtemplate, context=formatContext)
            # some pending reasons can be a problem with the receiver account, we should keep track of them
            if ourFault:
                paypalutil.log_ipn(ipnObj, 'Unhandled pending error')
        elif donation.transactionstate == 'COMPLETED':
            if donation.event.donationemailtemplate != None:
                formatContext = {
                    'donation': donation,
                    'donor': donation.donor,
                    'event': donation.event,
                    'prizes': viewutil.get_donation_prize_info(donation),
                }
                post_office.mail.send(recipients=[donation.donor.email], sender=donation.event.donationemailsender,
                                      template=donation.event.donationemailtemplate, context=formatContext)
            eventutil.post_donation_to_postbacks(donation)

        elif donation.transactionstate == 'CANCELLED':
            # eventually we may want to send out e-mail for some of the possible cases
            # such as payment reversal due to double-transactions (this has happened before)
            paypalutil.log_ipn(ipnObj, 'Cancelled/reversed payment')

    except Exception as inst:
        # just to make sure we have a record of it somewhere
        print("ERROR IN IPN RESPONSE, FIX IT")
        if ipnObj:
            paypalutil.log_ipn(ipnObj, "{0} \n {1}. POST data : {2}".format(
                inst, traceback.format_exc(inst), request.POST))
        else:
            viewutil.tracker_log('paypal', 'IPN creation failed: {0} \n {1}. POST data : {2}'.format(
                inst, traceback.format_exc(inst), request.POST))
    return HttpResponse("OKAY")
Example #8
0
def refresh_schedule(request):
    from django.contrib.auth.models import User
    try:
        id, username = request.META['HTTP_X_GOOG_CHANNEL_TOKEN'].split(':')
        event = Event.objects.get(id=id)
    except (ValueError, Event.DoesNotExist):
        return HttpResponse(json.dumps({'result': 'Event not found'}), status=404, content_type='application/json;charset=utf-8')
    viewutil.merge_schedule_gdoc(event, username)
    viewutil.tracker_log(u'schedule', u'Merged schedule via push for event {0}'.format(event), event=event,
                         user=User.objects.filter(username=username).first())
    return HttpResponse(json.dumps({'result': 'Merged successfully'}), content_type='application/json;charset=utf-8')
Example #9
0
 def cleanup_orphaned_donations(self, request, queryset):
   count = 0
   for donation in queryset.filter(donor=None, domain='PAYPAL', transactionstate='PENDING', timereceived__lte=datetime.utcnow() - timedelta(hours=8)):
     for bid in donation.bids.all():
       bid.delete()
     for ticket in donation.tickets.all():
       ticket.delete()
     donation.delete()
     count += 1
   self.message_user(request, "Deleted %d donations." % count)
   viewutil.tracker_log(u'donation', u'Deleted {0} orphaned donations'.format(count), user=request.user)
Example #10
0
def refresh_schedule(request):
    from django.contrib.auth.models import User
    try:
        id, username = request.META['HTTP_X_GOOG_CHANNEL_TOKEN'].split(':')
        event = Event.objects.get(id=id)
    except (ValueError, Event.DoesNotExist):
        return HttpResponse(json.dumps({'result': 'Event not found'}), status=404, content_type='application/json;charset=utf-8')
    viewutil.merge_schedule_gdoc(event, username)
    viewutil.tracker_log(u'schedule', u'Merged schedule via push for event {0}'.format(event), event=event,
                         user=User.objects.filter(username=username).first())
    return HttpResponse(json.dumps({'result': 'Merged successfully'}), content_type='application/json;charset=utf-8')
Example #11
0
 def merge_schedule(self, request, queryset):
   if queryset.count() != 1:
     self.message_user(request, 'Only select one event for this action', level=messages.ERROR)
     return
   for event in queryset:
     numRuns = viewutil.merge_schedule_gdoc(event)
     self.message_user(request, "%d runs merged for %s." % (numRuns, event.name))
     viewutil.tracker_log(u'schedule', u'Merged schedule for event {0}'.format(event), event=event, user=request.user)
   for event in queryset:
     result = event.start_push_notification(request)
     if result == True:
       self.message_user(request, 'Push notification started for %s.' % event.name)
     elif result:
       return result
Example #12
0
def automail_prize_winners(request):
  currentEvent = viewutil.get_selected_event(request)
  if currentEvent == None:
    return HttpResponse("Please select an event first")
  prizewinners = prizemail.prize_winners_with_email_pending(currentEvent)
  if request.method == 'POST':
    form = forms.AutomailPrizeWinnersForm(prizewinners=prizewinners, data=request.POST)
    if form.is_valid():
      prizemail.automail_prize_winners(currentEvent, form.cleaned_data['prizewinners'], form.cleaned_data['emailtemplate'], sender=form.cleaned_data['fromaddress'], replyTo=form.cleaned_data['replyaddress'])
      viewutil.tracker_log(u'prize', u'Mailed prize notifications', event=currentEvent, user=request.user)
      return render(request, 'admin/automail_prize_winners_post.html', { 'prizewinners': form.cleaned_data['prizewinners'] })
  else:
    form = forms.AutomailPrizeWinnersForm(prizewinners=prizewinners)
  return render(request, 'admin/automail_prize_winners.html', { 'form': form })
Example #13
0
def automail_prize_contributors(
    event,
    prizes,
    mailTemplate,
    domain=settings.DOMAIN,
    sender=None,
    replyTo=None,
    verbosity=0,
    dry_run=False,
):
    sender, replyTo = event_sender_replyto_defaults(event, sender, replyTo)

    handlerDict = {}
    for prize in prizes:
        if prize.handler:
            prizeList = handlerDict.setdefault(prize.handler, [])
            prizeList.append(prize)
    for handler, prizeList in handlerDict.items():
        formatContext = {
            'user_index_url':
            domain + reverse('tracker:user_index'),
            'event':
            event,
            'handler':
            handler,
            'accepted_prizes':
            [prize for prize in prizeList if prize.state == 'ACCEPTED'],
            'denied_prizes':
            [prize for prize in prizeList if prize.state == 'DENIED'],
            'reply_address':
            replyTo,
        }
        if not dry_run:
            post_office.mail.send(
                recipients=[handler.email],
                sender=sender,
                template=mailTemplate,
                context=formatContext,
                headers={'Reply-to': replyTo},
            )
        message = 'Mailed prize handler {0} for prizes {1}'.format(
            handler.id, [p.id for p in prizeList])
        if verbosity > 0:
            print(message)
        if not dry_run:
            viewutil.tracker_log('prize', message, event)
            for prize in prizeList:
                prize.acceptemailsent = True
                prize.save()
Example #14
0
    def automail_prize_contributors(request, event=None):
        if not hasattr(settings, 'EMAIL_HOST'):
            return HttpResponse('Email not enabled on this server.')
        event = viewutil.get_event(event)

        if not event.id:
            return render(
                request,
                'tracker/eventlist.html',
                {
                    'events': models.Event.objects.all(),
                    'pattern': 'admin:automail_prize_contributors',
                    'subheading': 'Mail Prize Contributors',
                },
            )

        prizes = prizemail.prizes_with_submission_email_pending(event)
        if request.method == 'POST':
            form = forms.AutomailPrizeContributorsForm(prizes=prizes,
                                                       data=request.POST)
            if form.is_valid():
                prizemail.automail_prize_contributors(
                    event,
                    form.cleaned_data['prizes'],
                    form.cleaned_data['emailtemplate'],
                    sender=form.cleaned_data['fromaddress'],
                    replyTo=form.cleaned_data['replyaddress'],
                )
                viewutil.tracker_log(
                    'prize',
                    'Mailed prize contributors',
                    event=event,
                    user=request.user,
                )
                return render(
                    request,
                    'admin/tracker/automail_prize_contributors_post.html',
                    {'prizes': form.cleaned_data['prizes']},
                )
        else:
            form = forms.AutomailPrizeContributorsForm(prizes=prizes)
        return render(
            request,
            'admin/tracker/automail_prize_contributors.html',
            {
                'form': form,
                'event': event
            },
        )
Example #15
0
def automail_prize_contributors(request):
  if not hasattr(settings, 'EMAIL_HOST'):
    return HttpResponse("Email not enabled on this server.")
  currentEvent = viewutil.get_selected_event(request)
  if currentEvent == None:
    return HttpResponse("Please select an event first")
  prizes = prizemail.prizes_with_submission_email_pending(currentEvent)
  if request.method == 'POST':
    form = forms.AutomailPrizeContributorsForm(prizes=prizes, data=request.POST)
    if form.is_valid():
      prizemail.automail_prize_contributors(currentEvent, form.cleaned_data['prizes'], form.cleaned_data['emailtemplate'], sender=form.cleaned_data['fromaddress'], replyTo=form.cleaned_data['replyaddress'])
      viewutil.tracker_log(u'prize', u'Mailed prize contributors', event=currentEvent, user=request.user)
      return render(request, 'admin/automail_prize_contributors_post.html', { 'prizes': form.cleaned_data['prizes'] })
  else:
    form = forms.AutomailPrizeContributorsForm(prizes=prizes)
  return render(request, 'admin/automail_prize_contributors.html', { 'form': form, 'currentEvent': currentEvent })
def log_ipn(ipnObj, message=''):
  donation = get_ipn_donation(ipnObj)
  message = "{message}\ntxn_id : {txn_id}\nstatus : {status}\nemail : {email}\namount : {amount}\ndate : {date}\ncustom : {custom}\ndonation : {donation}".format(
  **{ "message"  : message,
      "txn_id"   : ipnObj.txn_id,
      "status"   : ipnObj.payment_status,
      "email"    : ipnObj.payer_email,
      "amount"   : ipnObj.mc_gross,
      "date"     : ipnObj.payment_date,
      "custom"   : ipnObj.custom,
      "donation" : donation, })
  status = ipnObj.payment_status.lower()
  if status == 'pending':
    message += 'pending : ' + ipnObj.pending_reason
  elif status in ['reversed', 'refunded', 'canceled_reversal', 'denied']:
    message += 'reason  : ' + ipnObj.reason_code
  viewutil.tracker_log('paypal', message, event=donation.event if donation else None)
Example #17
0
def log_ipn(ipnObj, message=''):
  donation = get_ipn_donation(ipnObj)
  message = "{message}\ntxn_id : {txn_id}\nstatus : {status}\nemail : {email}\namount : {amount}\ndate : {date}\ncustom : {custom}\ndonation : {donation}".format(
  **{ "message"  : message,
      "txn_id"   : ipnObj.txn_id,
      "status"   : ipnObj.payment_status,
      "email"    : ipnObj.payer_email,
      "amount"   : ipnObj.mc_gross,
      "date"     : ipnObj.payment_date,
      "custom"   : ipnObj.custom,
      "donation" : donation, })
  status = ipnObj.payment_status.lower()
  if status == 'pending':
    message += 'pending : ' + ipnObj.pending_reason
  elif status in ['reversed', 'refunded', 'canceled_reversal', 'denied']:
    message += 'reason  : ' + ipnObj.reason_code
  viewutil.tracker_log('paypal', message, event=donation.event if donation else None)
Example #18
0
 def cleanup_orphaned_donations(self, request, queryset):
     count = 0
     for donation in queryset.filter(
             donor=None,
             domain='PAYPAL',
             transactionstate='PENDING',
             timereceived__lte=datetime.utcnow() - timedelta(hours=8),
     ):
         for bid in donation.bids.all():
             bid.delete()
         donation.delete()
         count += 1
     self.message_user(request, 'Deleted %d donations.' % count)
     viewutil.tracker_log(
         'donation',
         'Deleted {0} orphaned donations'.format(count),
         user=request.user,
     )
def automail_winner_accepted_prize(
    event,
    prizeWinners,
    mailTemplate,
    domain=settings.DOMAIN,
    sender=None,
    replyTo=None,
    verbosity=0,
    dry_run=False,
):
    sender, replyTo = event_sender_replyto_defaults(event, sender, replyTo)

    handlerDict = {}
    for prizeWinner in prizeWinners:
        if prizeWinner.prize.handler:
            prizeList = handlerDict.setdefault(prizeWinner.prize.handler, [])
            prizeList.append(prizeWinner)
    for handler, prizeList in handlerDict.items():
        formatContext = {
            'user_index_url': domain + reverse('tracker:user_index'),
            'prize_wins': prizeList,
            'prize_count': len(prizeList),
            'handler': handler,
            'event': event,
            'reply_address': replyTo,
        }
        if not dry_run:
            post_office.mail.send(
                recipients=[handler.email],
                sender=sender,
                template=mailTemplate,
                context=formatContext,
                headers={'Reply-to': replyTo},
            )
        message = 'Mailed handler {0} for prize accepts {1}'.format(
            handler.id, list([pw.id for pw in prizeList])
        )
        if verbosity > 0:
            print(message)
        if not dry_run:
            viewutil.tracker_log('prize', message, event)
            for prizeWinner in prizeList:
                prizeWinner.acceptemailsentcount = prizeWinner.acceptcount
                prizeWinner.save()
Example #20
0
def automail_prize_winners(request):
  if not hasattr(settings, 'EMAIL_HOST'):
    return HttpResponse("Email not enabled on this server.")
  currentEvent = viewutil.get_selected_event(request)
  if currentEvent == None:
    return HttpResponse("Please select an event first")
  prizewinners = prizemail.prize_winners_with_email_pending(currentEvent)
  if request.method == 'POST':
    form = forms.AutomailPrizeWinnersForm(prizewinners=prizewinners, data=request.POST)
    if form.is_valid():
      for prizeWinner in form.cleaned_data['prizewinners']:
        prizeWinner.acceptdeadline = form.cleaned_data['acceptdeadline']
        prizeWinner.save()
      prizemail.automail_prize_winners(currentEvent, form.cleaned_data['prizewinners'], form.cleaned_data['emailtemplate'], sender=form.cleaned_data['fromaddress'], replyTo=form.cleaned_data['replyaddress'])
      viewutil.tracker_log(u'prize', u'Mailed prize winner notifications', event=currentEvent, user=request.user)
      return render(request, 'admin/automail_prize_winners_post.html', { 'prizewinners': form.cleaned_data['prizewinners'] })
  else:
    form = forms.AutomailPrizeWinnersForm(prizewinners=prizewinners)
  return render(request, 'admin/automail_prize_winners.html', { 'form': form })
def automail_shipping_email_notifications(
    event,
    prizeWinners,
    mailTemplate,
    domain=settings.DOMAIN,
    sender=None,
    replyTo=None,
    verbosity=0,
    dry_run=False,
):
    sender, replyTo = event_sender_replyto_defaults(event, sender, replyTo)

    winnerDict = {}
    for prizeWinner in prizeWinners:
        prizeList = winnerDict.setdefault(prizeWinner.winner, [])
        prizeList.append(prizeWinner)
    for winner, prizeList in winnerDict.items():
        formatContext = {
            'prize_wins': prizeList,
            'prize_count': len(prizeList),
            'winner': winner,
            'event': event,
            'reply_address': replyTo,
        }
        if not dry_run:
            post_office.mail.send(
                recipients=[winner.email],
                sender=sender,
                template=mailTemplate,
                context=formatContext,
                headers={'Reply-to': replyTo},
            )
        message = 'Mailed donor {0} for prizes shipped {1}'.format(
            winner.id, list([pw.id for pw in prizeList])
        )
        if verbosity > 0:
            print(message)
        if not dry_run:
            viewutil.tracker_log('prize', message, event)
            for prizeWinner in prizeList:
                prizeWinner.shippingemailsent = True
                prizeWinner.save()
def log_ipn(ipnObj, message=''):
    donation = get_ipn_donation(ipnObj)
    message = '{message}\ntxn_id : {txn_id}\nstatus : {status}\nemail : {email}\namount : {amount}\ndate : {date}\ncustom : {custom}\ndonation : {donation}'.format(
        **{
            'message': message,
            'txn_id': ipnObj.txn_id,
            'status': ipnObj.payment_status,
            'email': ipnObj.payer_email,
            'amount': ipnObj.mc_gross,
            'date': ipnObj.payment_date,
            'custom': ipnObj.custom,
            'donation': donation,
        }
    )
    status = ipnObj.payment_status.lower()
    if status == 'pending':
        message += 'pending : ' + ipnObj.pending_reason
    elif status in ['reversed', 'refunded', 'canceled_reversal', 'denied']:
        message += 'reason  : ' + ipnObj.reason_code
    viewutil.tracker_log('paypal', message, event=donation.event if donation else None)
def automail_inactive_prize_handlers(event, inactiveUsers, mailTemplate, sender=None, replyTo=None, domain=settings.DOMAIN, verbosity=0, dry_run=False):
    sender, replyTo = event_sender_replyto_defaults(event, sender, replyTo)
    for inactiveUser in inactiveUsers:
        eventPrizes = list(Prize.objects.filter(handler=inactiveUser, event=event, state='ACCEPTED'))
        formatContext = {
            'event': event,
            'handler': inactiveUser,
            'register_url': domain + reverse('register'),
            'prize_set': eventPrizes,
            'prize_count': len(eventPrizes),
            'reply_address': replyTo,
        }
        if not dry_run:
            post_office.mail.send(recipients=[inactiveUser.email], sender=sender,
                template=mailTemplate, context=formatContext, headers={'Reply-to': replyTo})
        message = 'Mailed prize handler {0} (#{1}) for account activation'.format(inactiveUser, inactiveUser.id)
        if verbosity > 0:
            print(message)
        if not dry_run:
            viewutil.tracker_log('prize', message, event)
Example #24
0
def automail_inactive_prize_handlers(event, inactiveUsers, mailTemplate, sender=None, replyTo=None, domain=settings.DOMAIN, verbosity=0, dry_run=False):
    sender, replyTo = event_sender_replyto_defaults(event, sender, replyTo)
    for inactiveUser in inactiveUsers:
        eventPrizes = list(Prize.objects.filter(handler=inactiveUser, event=event, state='ACCEPTED'))
        formatContext = {
            'event': event,
            'handler': inactiveUser,
            'register_url': domain + reverse('tracker:register'),
            'prize_set': eventPrizes,
            'prize_count': len(eventPrizes),
            'reply_address': replyTo,
        }
        if not dry_run:
            post_office.mail.send(recipients=[inactiveUser.email], sender=sender,
                template=mailTemplate, context=formatContext, headers={'Reply-to': replyTo})
        message = 'Mailed prize handler {0} (#{1}) for account activation'.format(inactiveUser, inactiveUser.id)
        if verbosity > 0:
            print(message)
        if not dry_run:
            viewutil.tracker_log('prize', message, event)
def automail_prize_winners(event, prizeWinners, mailTemplate, sender=None, replyTo=None, domain=settings.DOMAIN, verbosity=0, dry_run=False):
    sender, replyTo = event_sender_replyto_defaults(event, sender, replyTo)
    
    winnerDict = {}
    for prizeWinner in prizeWinners:
        if prizeWinner.winner.id in winnerDict.keys():
            winList = winnerDict[prizeWinner.winner.id]
        else:
            winList = []
            winnerDict[prizeWinner.winner.id] = winList
        winList.append(prizeWinner)
    for winnerk, prizesWon in winnerDict.iteritems():
        winner = prizesWon[0].winner
        prizesList = []
        minAcceptDeadline = min(itertools.chain(filter(lambda x: x != None, map(lambda pw: pw.accept_deadline_date(), prizesWon)), [datetime.date.max]))

        for prizeWon in prizesWon:
            prizesList.append(prizeWon.prize)
        formatContext = {
            'event': event,
            'winner': winner,
            'prize_wins': prizesWon,
            'multi': len(prizesWon) > 1,
            'prize_count': len(prizesWon),
            'reply_address': replyTo,
            'accept_deadline': minAcceptDeadline,
        }

        if not dry_run:
            post_office.mail.send(recipients=[winner.email], sender=sender,
                              template=mailTemplate, context=formatContext, headers={'Reply-to': replyTo})

        message = 'Mailed donor {0} for prize wins {1}'.format(winner.id, list(map(lambda pw: pw.id, prizesWon)))

        if verbosity > 0:
            print(message)
        if not dry_run:
            viewutil.tracker_log('prize', message, event)
            for prizeWon in prizesWon:
                prizeWon.emailsent = True
                prizeWon.save()
Example #26
0
 def automail_prize_contributors(request):
     if not hasattr(settings, 'EMAIL_HOST'):
         return HttpResponse('Email not enabled on this server.')
     currentEvent = viewutil.get_selected_event(request)
     if currentEvent is None:
         return HttpResponse('Please select an event first')
     prizes = prizemail.prizes_with_submission_email_pending(currentEvent)
     if request.method == 'POST':
         form = forms.AutomailPrizeContributorsForm(prizes=prizes,
                                                    data=request.POST)
         if form.is_valid():
             prizemail.automail_prize_contributors(
                 currentEvent,
                 form.cleaned_data['prizes'],
                 form.cleaned_data['emailtemplate'],
                 sender=form.cleaned_data['fromaddress'],
                 replyTo=form.cleaned_data['replyaddress'],
             )
             viewutil.tracker_log(
                 'prize',
                 'Mailed prize contributors',
                 event=currentEvent,
                 user=request.user,
             )
             return render(
                 request,
                 'admin/automail_prize_contributors_post.html',
                 {'prizes': form.cleaned_data['prizes']},
             )
     else:
         form = forms.AutomailPrizeContributorsForm(prizes=prizes)
     return render(
         request,
         'admin/automail_prize_contributors.html',
         {
             'form': form,
             'currentEvent': currentEvent
         },
     )
Example #27
0
def post_donation_to_postbacks(donation):
    event_donations = filters.run_model_query('donation',
                                              {'event': donation.event.id})
    total = event_donations.aggregate(amount=Sum('amount'))['amount']

    data = {
        'id': donation.id,
        'timereceived': str(donation.timereceived),
        'comment': donation.comment,
        'amount': float(donation.amount),
        'donor__visibility': donation.donor.visibility,
        'donor__visiblename': donation.donor.visible_name(),
        'new_total': float(total),
        'domain': donation.domain,
    }

    async_to_sync(get_channel_layer().group_send)('donations', {
        'type': 'donation',
        **data
    })

    try:
        data_json = json.dumps(
            data, ensure_ascii=False,
            cls=serializers.json.DjangoJSONEncoder).encode('utf-8')

        postbacks = models.PostbackURL.objects.filter(event=donation.event)
        for postback in postbacks:
            opener = urllib.request.build_opener()
            req = urllib.request.Request(
                postback.url,
                data_json,
                headers={'Content-Type': 'application/json; charset=utf-8'},
            )
            opener.open(req, timeout=5)
    except Exception:
        viewutil.tracker_log('postback_url',
                             traceback.format_exc(),
                             event=donation.event)
Example #28
0
 def automail_prize_winners(request):
     if not hasattr(settings, 'EMAIL_HOST'):
         return HttpResponse('Email not enabled on this server.')
     currentEvent = viewutil.get_selected_event(request)
     if currentEvent is None:
         return HttpResponse('Please select an event first')
     prizewinners = prizemail.prize_winners_with_email_pending(currentEvent)
     if request.method == 'POST':
         form = forms.AutomailPrizeWinnersForm(prizewinners=prizewinners,
                                               data=request.POST)
         if form.is_valid():
             for prizeWinner in form.cleaned_data['prizewinners']:
                 prizeWinner.acceptdeadline = form.cleaned_data[
                     'acceptdeadline']
                 prizeWinner.save()
             prizemail.automail_prize_winners(
                 currentEvent,
                 form.cleaned_data['prizewinners'],
                 form.cleaned_data['emailtemplate'],
                 sender=form.cleaned_data['fromaddress'],
                 replyTo=form.cleaned_data['replyaddress'],
             )
             viewutil.tracker_log(
                 'prize',
                 'Mailed prize winner notifications',
                 event=currentEvent,
                 user=request.user,
             )
             return render(
                 request,
                 'admin/automail_prize_winners_post.html',
                 {'prizewinners': form.cleaned_data['prizewinners']},
             )
     else:
         form = forms.AutomailPrizeWinnersForm(prizewinners=prizewinners)
     return render(request, 'admin/automail_prize_winners.html',
                   {'form': form})
Example #29
0
def post_donation_to_postbacks(donation):
    event_donations = filters.run_model_query('donation',
                                              {'event': donation.event.id})
    total = event_donations.aggregate(amount=Sum('amount'))['amount']

    data = {
        'key': settings.SECRET_KEY,
        'id': donation.id,
        'timereceived': str(donation.timereceived),
        'comment': donation.comment,
        'amount': donation.amount,
        'donor__visibility': donation.donor.visibility,
        'donor__visiblename': donation.donor.visible_name(),
        'new_total': total,
        'domain': donation.domain
    }

    # XXX: django/urllib2 throws UnicodeDecideError when payloads contain
    # unicode codepoints:
    #   UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 292: ordinal not in range(128)
    try:
        data_json = json.dumps(
            data, ensure_ascii=False,
            cls=serializers.json.DjangoJSONEncoder).encode('utf-8')

        postbacks = models.PostbackURL.objects.filter(event=donation.event)
        for postback in postbacks:
            opener = urllib.request.build_opener()
            req = urllib.request.Request(
                postback.url,
                data_json,
                headers={'Content-Type': 'application/json; charset=utf-8'})
            response = opener.open(req, timeout=5)
    except Exception as e:
        viewutil.tracker_log('postback_url',
                             traceback.format_exc(),
                             event=donation.event)
Example #30
0
    def automail_prize_winners(request, event=None):
        if not hasattr(settings, 'EMAIL_HOST'):
            return HttpResponse('Email not enabled on this server.')

        event = viewutil.get_event(event)

        if not event.id:
            return render(
                request,
                'tracker/eventlist.html',
                {
                    'events': models.Event.objects.all(),
                    'pattern': 'admin:automail_prize_winners',
                    'subheading': 'Mail Prize Winners',
                },
            )

        import post_office.mail

        prizewinners = prizemail.prize_winners_with_email_pending(event)
        if request.method == 'POST':
            form = forms.AutomailPrizeWinnersForm(prizewinners=prizewinners,
                                                  data=request.POST)
            if form.is_valid():
                for winner, prizewins in groupby(
                        sorted(form.cleaned_data['prizewinners'],
                               key=lambda p: p.winner.id),
                        lambda p: p.winner,
                ):
                    prizewins = list(prizewins)

                    for prizewin in prizewins:
                        prizewin.create_claim_url(request)

                    format_context = {
                        'event': event,
                        'winner': winner,
                        'prize_wins': prizewins,
                        'multi': len(prizewins) > 1,
                        'prize_count': len(prizewins),
                        'reply_address': form.cleaned_data['replyaddress'],
                        'accept_deadline': form.cleaned_data['acceptdeadline'],
                    }

                    post_office.mail.send(
                        recipients=[winner.email],
                        sender=form.cleaned_data['fromaddress'],
                        template=form.cleaned_data['emailtemplate'],
                        context=format_context,
                        headers={
                            'Reply-to': form.cleaned_data['replyaddress']
                        },
                    )

                    for prizewin in prizewins:
                        prizewin.emailsent = True
                        # "anywhere on earth" Time Zone is GMT-12
                        prizewin.acceptdeadline = datetime.datetime.combine(
                            form.cleaned_data['acceptdeadline'] +
                            datetime.timedelta(days=1),
                            datetime.time(0, 0),
                        ).replace(tzinfo=pytz.timezone('Etc/GMT-12'))
                        prizewin.save()

                viewutil.tracker_log(
                    'prize',
                    'Mailed prize winner notifications',
                    event=event,
                    user=request.user,
                )
                return render(
                    request,
                    'admin/tracker/automail_prize_winners_post.html',
                    {'prizewinners': form.cleaned_data['prizewinners']},
                )
        else:
            form = forms.AutomailPrizeWinnersForm(prizewinners=prizewinners)
        return render(request, 'admin/tracker/automail_prize_winners.html',
                      {'form': form})
Example #31
0
def ipn(request):
  donation = None
  ipnObj = None

  if request.method == 'GET' or len(request.POST) == 0:
    return tracker_response(request, "tracker/badobject.html", {})

  try:
    ipnObj = paypalutil.create_ipn(request)
    ipnObj.save()

    donation = paypalutil.initialize_paypal_donation(ipnObj)
    donation.save()

    if donation.transactionstate == 'PENDING':
      reasonExplanation, ourFault = paypalutil.get_pending_reason_details(ipnObj.pending_reason)
      if donation.event.pendingdonationemailtemplate:
        formatContext = {
          'event': donation.event,
          'donation': donation,
          'donor': donor,
          'pending_reason': ipnObj.pending_reason,
          'reason_info': reasonExplanation if not ourFault else '',
        }
        post_office.mail.send(recipients=[donation.donor.email], sender=donation.event.donationemailsender, template=donation.event.pendingdonationemailtemplate, context=formatContext)
      # some pending reasons can be a problem with the receiver account, we should keep track of them
      if ourFault:
        paypalutil.log_ipn(ipnObj, 'Unhandled pending error')
    elif donation.transactionstate == 'COMPLETED':
      if donation.event.donationemailtemplate != None:
        formatContext = {
          'donation': donation,
          'donor': donation.donor,
          'event': donation.event,
          'prizes': viewutil.get_donation_prize_info(donation),
        }
        post_office.mail.send(recipients=[donation.donor.email], sender=donation.event.donationemailsender, template=donation.event.donationemailtemplate, context=formatContext)

      # TODO: this should eventually share code with the 'search' method, to
      postbackData = {
        'id': donation.id,
        'timereceived': str(donation.timereceived),
        'comment': donation.comment,
        'amount': donation.amount,
        'donor__visibility': donation.donor.visibility,
        'donor__visiblename': donation.donor.visible_name(),
      }
      postbackJSon = json.dumps(postbackData)
      postbacks = PostbackURL.objects.filter(event=donation.event)
      for postback in postbacks:
        opener = urllib2.build_opener()
        req = urllib2.Request(postback.url, postbackJSon, headers={'Content-Type': 'application/json; charset=utf-8'})
        response = opener.open(req, timeout=5)
    elif donation.transactionstate == 'CANCELLED':
      # eventually we may want to send out e-mail for some of the possible cases
      # such as payment reversal due to double-transactions (this has happened before)
      paypalutil.log_ipn(ipnObj, 'Cancelled/reversed payment')

  except Exception as inst:
    print(inst)
    print(traceback.format_exc(inst))
    if ipnObj:
      paypalutil.log_ipn(ipnObj, "{0} \n {1}. POST data : {2}".format(inst, traceback.format_exc(inst), request.POST))
    else:
      viewutil.tracker_log('paypal', 'IPN creation failed: {0} \n {1}. POST data : {2}'.format(inst, traceback.format_exc(inst), request.POST))

  return HttpResponse("OKAY")
Example #32
0
def initialize_paypal_donation(ipnObj):
  countrycode = ipnObj.residence_country if not ipnObj.address_country_code else ipnObj.address_country_code
  defaults = {
    'email'           : ipnObj.payer_email.lower(),
    'firstname'       : ipnObj.first_name,
    'lastname'        : ipnObj.last_name,
    'addressstreet'  : ipnObj.address_street,
    'addresscity'    : ipnObj.address_city,
    'addresscountry' : Country.objects.get(alpha2=countrycode),
    'addressstate'   : ipnObj.address_state,
    'addresszip'     : ipnObj.address_zip,
    'visibility'      : 'ANON',
  }
  donor,created = Donor.objects.get_or_create(paypalemail=ipnObj.payer_email.lower(),defaults=defaults)
  
  fill_donor_address(donor, ipnObj)

  donation = get_ipn_donation(ipnObj)

  if donation:
    if donation.requestedvisibility != 'CURR':
      donor.visibility = donation.requestedvisibility
    if donation.requestedalias and (not donor.alias or donation.requestedalias.lower() != donor.alias.lower()):
      foundAResult = False
      currentAlias = donation.requestedalias
      while not foundAResult:
        results = Donor.objects.filter(alias__iexact=currentAlias)
        if results.exists():
          currentAlias = donation.requestedalias + str(random.getrandbits(8))
        else:
          foundAResult = True
      donor.alias = currentAlias
    if donation.requestedemail and donation.requestedemail != donor.email and not Donor.objects.filter(email=donation.requestedemail).exists():
      donor.email = donation.requestedemail
    if donation.requestedsolicitemail != 'CURR':
      donor.solicitemail = donation.requestedsolicitemail
    donor.save()
  else:
    donation = Donation()
    donation.modcomment = '*Donation for ipn was not found, creating new*'
    donation.event = Event.objects.latest()

  donation.domain='PAYPAL'
  donation.domainId=ipnObj.txn_id
  donation.donor=donor
  donation.amount=Decimal(ipnObj.mc_gross)
  donation.currency=ipnObj.mc_currency
  if not donation.timereceived:
    donation.timereceived = datetime.utcnow()
  donation.testdonation=ipnObj.test_ipn
  donation.fee=Decimal(ipnObj.mc_fee or 0)

  # if the user attempted to tamper with the donation amount, remove all bids
  if donation.amount != ipnObj.mc_gross:
    donation.modcomment += u"\n*Tampered donation amount from " + str(donation.amount) + u" to " + str(ipnObj.mc_gross) + u", removed all bids*"
    donation.amount = ipnObj.mc_gross
    donation.bids.clear()
    viewutil.tracker_log('paypal', 'Tampered amount detected in donation {0} (${1} -> ${2})'.format(donation.id, donation.amount, ipnObj.mc_gross), event=donation.event) 

  paymentStatus = ipnObj.payment_status.lower()

  if not ipnObj.flag:
    if paymentStatus == 'pending':
      donation.transactionstate = 'PENDING'
    elif paymentStatus == 'completed' or paymentStatus == 'canceled_reversal' or paymentStatus == 'processed':
      donation.transactionstate = 'COMPLETED'
    elif paymentStatus == 'refunded' or paymentStatus == 'reversed' or paymentStatus == 'failed' or paymentStatus == 'voided' or paymentStatus == 'denied':
      donation.transactionstate = 'CANCELLED'
    else:
      donation.transactionstate = 'FLAGGED'
      viewutil.tracker_log('paypal', 'Unknown payment status in donation {0} ({1})'.format(donation.id, paymentStatus), event=donation.event)
  else:
    donation.transactionstate = 'FLAGGED'
    viewutil.tracker_log('paypal', 'IPN object flagged for donation {0} ({1})'.format(donation.id, ipnObj.txn_id), event=donation.event)

  donation.save()
  # I think we only care if the _donation_ was freshly created
  return donation
def initialize_paypal_donation(ipnObj):
    countrycode = ipnObj.residence_country if not ipnObj.address_country_code else ipnObj.address_country_code
    defaults = {
        'email': ipnObj.payer_email.lower(),
        'firstname': ipnObj.first_name,
        'lastname': ipnObj.last_name,
        'addressstreet': ipnObj.address_street,
        'addresscity': ipnObj.address_city,
        'addresscountry': Country.objects.get(alpha2=countrycode),
        'addressstate': ipnObj.address_state,
        'addresszip': ipnObj.address_zip,
        'visibility': 'ANON',
    }
    donor, created = Donor.objects.get_or_create(
        paypalemail=ipnObj.payer_email.lower(), defaults=defaults)

    fill_donor_address(donor, ipnObj)

    donation = get_ipn_donation(ipnObj)

    if donation:
        if donation.requestedvisibility != 'CURR':
            donor.visibility = donation.requestedvisibility
        if donation.requestedalias and (not donor.alias or donation.requestedalias.lower() != donor.alias.lower()):
            foundAResult = False
            currentAlias = donation.requestedalias
            while not foundAResult:
                results = Donor.objects.filter(alias__iexact=currentAlias)
                if results.exists():
                    currentAlias = donation.requestedalias + \
                        str(random.getrandbits(8))
                else:
                    foundAResult = True
            donor.alias = currentAlias
        if donation.requestedemail and donation.requestedemail != donor.email and not Donor.objects.filter(email=donation.requestedemail).exists():
            donor.email = donation.requestedemail
        if donation.requestedsolicitemail != 'CURR':
            donor.solicitemail = donation.requestedsolicitemail
        donor.save()
    else:
        donation = Donation()
        donation.modcomment = '*Donation for ipn was not found, creating new*'
        donation.event = Event.objects.latest()

    donation.domain = 'PAYPAL'
    donation.domainId = ipnObj.txn_id
    donation.donor = donor
    donation.amount = Decimal(ipnObj.mc_gross)
    donation.currency = ipnObj.mc_currency
    if not donation.timereceived:
        donation.timereceived = datetime.utcnow()
    donation.testdonation = ipnObj.test_ipn
    donation.fee = Decimal(ipnObj.mc_fee or 0)

    # if the user attempted to tamper with the donation amount, remove all bids
    if donation.amount != ipnObj.mc_gross:
        donation.modcomment += u"\n*Tampered donation amount from " + \
            str(donation.amount) + u" to " + \
            str(ipnObj.mc_gross) + u", removed all bids*"
        donation.amount = ipnObj.mc_gross
        donation.bids.clear()
        viewutil.tracker_log('paypal', 'Tampered amount detected in donation {0} (${1} -> ${2})'.format(
            donation.id, donation.amount, ipnObj.mc_gross), event=donation.event)

    paymentStatus = ipnObj.payment_status.lower()

    if not ipnObj.flag:
        if paymentStatus == 'pending':
            donation.transactionstate = 'PENDING'
        elif paymentStatus == 'completed' or paymentStatus == 'canceled_reversal' or paymentStatus == 'processed':
            donation.transactionstate = 'COMPLETED'
        elif paymentStatus == 'refunded' or paymentStatus == 'reversed' or paymentStatus == 'failed' or paymentStatus == 'voided' or paymentStatus == 'denied':
            donation.transactionstate = 'CANCELLED'
        else:
            donation.transactionstate = 'FLAGGED'
            viewutil.tracker_log('paypal', 'Unknown payment status in donation {0} ({1})'.format(
                donation.id, paymentStatus), event=donation.event)
    else:
        donation.transactionstate = 'FLAGGED'
        viewutil.tracker_log('paypal', 'IPN object flagged for donation {0} ({1})'.format(
            donation.id, ipnObj.txn_id), event=donation.event)

    donation.save()
    # I think we only care if the _donation_ was freshly created
    return donation
Example #34
0
def ipn(request):
    ipnObj = None

    if request.method == 'GET' or len(request.POST) == 0:
        return views_common.tracker_response(request, "tracker/badobject.html",
                                             {})

    try:
        ipnObj = paypalutil.create_ipn(request)
        ipnObj.save()

        donation = paypalutil.initialize_paypal_donation(ipnObj)
        donation.save()

        if donation.transactionstate == 'PENDING':
            reasonExplanation, ourFault = paypalutil.get_pending_reason_details(
                ipnObj.pending_reason)
            if donation.event.pendingdonationemailtemplate:
                formatContext = {
                    'event': donation.event,
                    'donation': donation,
                    'donor': donation.donor,
                    'pending_reason': ipnObj.pending_reason,
                    'reason_info': reasonExplanation if not ourFault else '',
                }
                post_office.mail.send(
                    recipients=[donation.donor.email],
                    sender=donation.event.donationemailsender,
                    template=donation.event.pendingdonationemailtemplate,
                    context=formatContext)
            # some pending reasons can be a problem with the receiver account, we should keep track of them
            if ourFault:
                paypalutil.log_ipn(ipnObj, 'Unhandled pending error')
        elif donation.transactionstate == 'COMPLETED':
            if donation.event.donationemailtemplate != None:
                formatContext = {
                    'donation': donation,
                    'donor': donation.donor,
                    'event': donation.event,
                    'prizes': viewutil.get_donation_prize_info(donation),
                }
                post_office.mail.send(
                    recipients=[donation.donor.email],
                    sender=donation.event.donationemailsender,
                    template=donation.event.donationemailtemplate,
                    context=formatContext)

            agg = filters.run_model_query('donation', {
                'event': donation.event.id
            }).aggregate(amount=Sum('amount'))

            # TODO: this should eventually share code with the 'search' method, to
            postbackData = {
                'id': donation.id,
                'timereceived': str(donation.timereceived),
                'comment': donation.comment,
                'amount': donation.amount,
                'donor__visibility': donation.donor.visibility,
                'donor__visiblename': donation.donor.visible_name(),
                'new_total': agg['amount']
            }
            postbackJSon = json.dumps(
                postbackData,
                ensure_ascii=False,
                cls=serializers.json.DjangoJSONEncoder).encode('utf-8')
            postbacks = models.PostbackURL.objects.filter(event=donation.event)
            for postback in postbacks:
                opener = urllib.request.build_opener()
                req = urllib.request.Request(
                    postback.url,
                    postbackJSon,
                    headers={
                        'Content-Type': 'application/json; charset=utf-8'
                    })
                response = opener.open(req, timeout=5)
        elif donation.transactionstate == 'CANCELLED':
            # eventually we may want to send out e-mail for some of the possible cases
            # such as payment reversal due to double-transactions (this has happened before)
            paypalutil.log_ipn(ipnObj, 'Cancelled/reversed payment')

    except Exception as inst:
        # just to make sure we have a record of it somewhere
        print("ERROR IN IPN RESPONSE, FIX IT")
        if ipnObj:
            paypalutil.log_ipn(
                ipnObj, "{0} \n {1}. POST data : {2}".format(
                    inst, traceback.format_exc(inst), request.POST))
        else:
            viewutil.tracker_log(
                'paypal',
                'IPN creation failed: {0} \n {1}. POST data : {2}'.format(
                    inst, traceback.format_exc(inst), request.POST))
    return HttpResponse("OKAY")
def initialize_paypal_donation(ipnObj):
    defaults = {
        "email": ipnObj.payer_email.lower(),
        "firstname": ipnObj.first_name,
        "lastname": ipnObj.last_name,
        "addressstreet": ipnObj.address_street,
        "addresscity": ipnObj.address_city,
        "addresscountry": ipnObj.address_country,
        "addressstate": ipnObj.address_state,
        "addresszip": ipnObj.address_zip,
        "visibility": "ANON",
    }
    donor, created = Donor.objects.get_or_create(paypalemail=ipnObj.payer_email.lower(), defaults=defaults)

    donation = get_ipn_donation(ipnObj)

    if donation:
        if donation.requestedvisibility != "CURR":
            donor.visibility = donation.requestedvisibility
        if donation.requestedalias and (not donor.alias or donation.requestedalias.lower() != donor.alias.lower()):
            foundAResult = False
            currentAlias = donation.requestedalias
            while not foundAResult:
                results = Donor.objects.filter(alias__iexact=currentAlias)
                if results.exists():
                    currentAlias = donation.requestedalias + str(random.getrandbits(8))
                else:
                    foundAResult = True
            donor.alias = currentAlias
        if (
            donation.requestedemail
            and donation.requestedemail != donor.email
            and not Donor.objects.filter(email=donation.requestedemail).exists()
        ):
            donor.email = donation.requestedemail
        donor.save()
    else:
        donation = Donation()
        donation.modcomment = "*Donation for ipn was not found, creating new*"
        donation.event = Event.objects.latest()

    donation.domain = "PAYPAL"
    donation.domainId = ipnObj.txn_id
    donation.donor = donor
    donation.amount = Decimal(ipnObj.mc_gross)
    donation.currency = ipnObj.mc_currency
    if not donation.timereceived:
        donation.timereceived = datetime.utcnow()
    donation.testdonation = ipnObj.test_ipn
    donation.fee = Decimal(ipnObj.mc_fee or 0)

    # if the user attempted to tamper with the donation amount, remove all bids
    if donation.amount != ipnObj.mc_gross:
        donation.modcomment += (
            u"\n*Tampered donation amount from "
            + str(donation.amount)
            + u" to "
            + str(ipnObj.mc_gross)
            + u", removed all bids*"
        )
        donation.amount = ipnObj.mc_gross
        donation.bids.clear()
        viewutil.tracker_log(
            "paypal",
            "Tampered amount detected in donation {0} (${1} -> ${2})".format(
                donation.id, donation.amount, ipnObj.mc_gross
            ),
            event=donation.event,
        )

    paymentStatus = ipnObj.payment_status.lower()

    if not ipnObj.flag:
        if paymentStatus == "pending":
            donation.transactionstate = "PENDING"
        elif paymentStatus == "completed" or paymentStatus == "canceled_reversal" or paymentStatus == "processed":
            donation.transactionstate = "COMPLETED"
        elif (
            paymentStatus == "refunded"
            or paymentStatus == "reversed"
            or paymentStatus == "failed"
            or paymentStatus == "voided"
            or paymentStatus == "denied"
        ):
            donation.transactionstate = "CANCELLED"
        else:
            donation.transactionstate = "FLAGGED"
            viewutil.tracker_log(
                "paypal",
                "Unknown payment status in donation {0} ({1})".format(donation.id, paymentStatus),
                event=donation.event,
            )
    else:
        donation.transactionstate = "FLAGGED"
        viewutil.tracker_log(
            "paypal",
            "IPN object flagged for donation {0} ({1})".format(donation.id, ipnObj.txn_id),
            event=donation.event,
        )

    donation.save()
    # I think we only care if the _donation_ was freshly created
    return donation