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)
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")
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 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')
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)
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
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 })
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()
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 }, )
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)
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()
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)
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()
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 }, )
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)
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})
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)
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})
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")
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
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