def send_incomplete_pledge_emails(self):
		# For every IncompletePledge instance that has not yet been
		# sent a reminder email, send one. Wait at least some hours
		# after the user left the page.
		before = timezone.now() - timedelta(hours=3)
		for ip in IncompletePledge.objects.filter(created__lt=before, sent_followup_at=None):
			context = { }
			context.update(get_branding(ip.via_campaign.brand))
			context.update({
				"incomplete_pledge": ip,
				"url": ip.get_return_url(),
				"trigger": ip.trigger,
			})

			# Send email.
			send_mail(
				"contrib/mail/incomplete_pledge",
				get_branding(ip.via_campaign.brand)["MAIL_FROM_EMAIL"],
				[ip.email],
				context,
				headers={
					"Reply-To": get_branding(ip.via_campaign.brand)["CONTACT_EMAIL"],
				})

			# Record that it was sent.
			ip.sent_followup_at = timezone.now()
			ip.save()
Ejemplo n.º 2
0
    def send_incomplete_pledge_emails(self):
        # For every IncompletePledge instance that has not yet been
        # sent a reminder email, send one. Wait at least some hours
        # after the user left the page.
        before = timezone.now() - timedelta(hours=3)
        for ip in IncompletePledge.objects.filter(created__lt=before,
                                                  sent_followup_at=None):
            context = {}
            context.update(get_branding(ip.via_campaign.brand))
            context.update({
                "incomplete_pledge": ip,
                "url": ip.get_return_url(),
                "trigger": ip.trigger,
            })

            # Send email.
            send_mail("contrib/mail/incomplete_pledge",
                      get_branding(ip.via_campaign.brand)["MAIL_FROM_EMAIL"],
                      [ip.email],
                      context,
                      headers={
                          "Reply-To":
                          get_branding(ip.via_campaign.brand)["CONTACT_EMAIL"],
                      })

            # Record that it was sent.
            ip.sent_followup_at = timezone.now()
            ip.save()
Ejemplo n.º 3
0
def render_pledge_template(request,
                           pledge,
                           campaign,
                           show_long_title=False,
                           response_page=False):
    # Get the user's pledges, if any, on any trigger tied to this campaign.
    import django.template
    template = django.template.loader.get_template("contrib/contrib.html")

    ctx = {
        "response_page":
        response_page,
        "show_long_title":
        show_long_title,
        "pledge":
        pledge,
        "campaign":
        campaign,
        "execution":
        PledgeExecution.objects.filter(pledge=pledge).first(),
        "contribs":
        sorted(Contribution.objects.filter(
            pledge_execution__pledge=pledge).select_related(
                "action", "recipient"),
               key=lambda c: (c.recipient_type.value, c.action.name_sort)),
        "share_url":
        request.build_absolute_uri(pledge.via_campaign.get_short_url()),
    }

    from itfsite.middleware import get_branding
    ctx.update(get_branding(request))

    return template.render(ctx)
Ejemplo n.º 4
0
    def send_pledge_email(self, pre_or_post, pledge):
        # What will happen when the pledge is executed?
        recipients = get_pledge_recipients(pledge)
        if len(recipients) == 0:
            # This pledge will result in nothing happening. There is
            # no need to email.
            return
        recip_contribs, fees, total_charge = compute_charge(pledge, recipients)

        context = {}
        context.update(get_branding(pledge.via_campaign.brand))
        context.update({
            "profile":
            pledge.profile,  # used in salutation in email_template
            "pledge":
            pledge,
            "until":
            Pledge.current_algorithm()['pre_execution_warn_time'][1],
            "total_charge":
            total_charge,
        })

        # Send email.
        send_mail("contrib/mail/%s_execution" % pre_or_post,
                  context["MAIL_FROM_EMAIL"], [pledge.user.email], context)

        # Record that it was sent.
        field_name = "%s_execution_email_sent_at" % pre_or_post
        setattr(pledge, field_name, timezone.now())
        pledge.save(update_fields=[field_name])
	def send_pledge_email(self, pre_or_post, pledge):
		# What will happen when the pledge is executed?
		recipients = get_pledge_recipients(pledge)
		if len(recipients) == 0:
			# This pledge will result in nothing happening. There is
			# no need to email.
			return
		recip_contribs, fees, total_charge = compute_charge(pledge, recipients)

		context = { }
		context.update(get_branding(pledge.via_campaign.brand))
		context.update({
			"profile": pledge.profile, # used in salutation in email_template
			"pledge": pledge,
			"until": Pledge.current_algorithm()['pre_execution_warn_time'][1],
			"total_charge": total_charge,
		})

		# Send email.
		send_mail(
			"contrib/mail/%s_execution" % pre_or_post,
			context["MAIL_FROM_EMAIL"],
			[pledge.user.email],
			context)

		# Record that it was sent.
		field_name = "%s_execution_email_sent_at" % pre_or_post
		setattr(pledge, field_name, timezone.now())
		pledge.save(update_fields=[field_name])
Ejemplo n.º 6
0
def render2(request, template, *args, **kwargs):
	import os.path
	from django.template import TemplateDoesNotExist
	template1 = os.path.join('branding', get_branding(request)['BRAND_ID'], 'templates', template)
	try:
		# Try a brand-specific template.
		return render(request, template1, *args, **kwargs)
	except TemplateDoesNotExist as e:
		# Raise if the template that doesn't exist is one that is loaded by an include tag.
		if hasattr(e, 'django_template_source'):
			raise
		# Try a default template.
		return render(request, template, *args, **kwargs)
Ejemplo n.º 7
0
def campaign(request, id, action, api_format_ext):
    # get the object, make sure it is for the right brand that the user is viewing
    campaign = get_object_or_404(Campaign,
                                 id=id,
                                 brand=get_branding(request)['BRAND_INDEX'])

    # redirect to canonical URL if slug does not match
    # (pass along any query string variables like utm_campaign; when
    # a .json page is requested, the canonical path omits the slug)
    if not api_format_ext:
        canonical_path = campaign.get_absolute_url() + (api_format_ext or "")
    else:
        canonical_path = "/a/%d%s" % (campaign.id, api_format_ext)
    if action:
        canonical_path += "/" + action
    qs = (("?" + request.META['QUERY_STRING'])
          if request.META['QUERY_STRING'] else "")
    if request.path != canonical_path:

        @anonymous_view
        def redirector(request):
            return redirect(canonical_path + qs)

        return redirector(request)

    # The rest of this view is handled in the next two functions.
    if action is None:
        f = campaign_show
    elif api_format_ext is not None:
        raise Http404()
    elif action == "contribute":
        f = campaign_action_trigger
    else:
        raise Http404()

    # Cache?
    if campaign.status == CampaignStatus.Draft:
        # When a campaign is in draft status, we won't
        # cache the output to allow the user editing the
        # campaign's settings to reload the page to see
        # updated settings.
        pass
    else:
        # As soon as the campaign exits draft status we'll
        # mark the response as cachable so that the http
        # layer strongly caches the output.
        pass  # f = anonymous_view(f)

    return f(request, campaign, api_format_ext == ".json")
Ejemplo n.º 8
0
def render2(request, template, *args, **kwargs):
    import os.path
    from django.template import TemplateDoesNotExist
    template1 = os.path.join('branding',
                             get_branding(request)['BRAND_ID'], 'templates',
                             template)
    try:
        # Try a brand-specific template.
        return render(request, template1, *args, **kwargs)
    except TemplateDoesNotExist as e:
        # Raise if the template that doesn't exist is one that is loaded by an include tag.
        if hasattr(e, 'django_template_source'):
            raise
        # Try a default template.
        return render(request, template, *args, **kwargs)
Ejemplo n.º 9
0
	def email_confirmation_response_view(self, request):
		# The user may be new, so take them to a welcome page.
		from itfsite.middleware import get_branding
		from itfsite.accounts import first_time_confirmed_user

		# Redirect to the most recent pledge of this user on
		# the same brand site as this request is on.
		from contrib.models import Pledge
		pledge = Pledge.objects.filter(
			user=self.confirmed_user,
			via_campaign__brand=get_branding(request)['BRAND_INDEX'],
			).order_by('-created').first()

		return first_time_confirmed_user(request, self.confirmed_user,
			pledge.get_absolute_url() if pledge else "/home")
Ejemplo n.º 10
0
		def mailer(context):
			from itfsite.middleware import get_branding
			context.update(get_branding(brand_id))

			context.update({
				"profile": profile, # used in salutation in email_template
				"pledge": pledge,
				"first_try": not self.sentConfirmationEmail,
			})
			
			from htmlemailer import send_mail
			send_mail(
				template,
				context["MAIL_FROM_EMAIL"],
				[context['email']],
				context)
Ejemplo n.º 11
0
def user_home(request):
    from contrib.models import Pledge, PledgeStatus

    # Get the user's actions that took place on the brand site that the user is actually on.
    brand_filter = {
        "via_campaign__brand": get_branding(request)['BRAND_INDEX']
    }
    pledges = Pledge.objects.filter(user=request.user,
                                    **brand_filter).prefetch_related()
    actions = list(pledges)
    actions.sort(key=lambda obj: obj.created, reverse=True)

    # Get the user's total amount of open pledges, i.e. their total possible
    # future credit card charges / campaign contributions.
    open_pledges = pledges.filter(status=PledgeStatus.Open)
    if len(open_pledges) == 0:
        total_pledged = 0.0
    else:
        total_pledged = open_pledges.aggregate(
            total_pledged=Sum('amount'))['total_pledged']

    # Get the user's total amount of executed campaign contributions.
    total_contribs = pledges.filter(status=PledgeStatus.Executed)
    if len(total_contribs) == 0:
        total_contribs = 0.0
    else:
        total_contribs = total_contribs.aggregate(
            total_contribs=Sum('execution__charged'))['total_contribs']

    # Get the user's distinct ContributorInfo objects on *open* Pledges,
    # indicating future submitted info.
    if len(open_pledges) == 0:
        profiles = []
    else:
        profiles = set(p.profile for p in open_pledges)

    return render(
        request, "itfsite/user_home.html", {
            'actions': actions,
            'profiles': profiles,
            'total_pledged': total_pledged,
            'total_contribs': total_contribs,
            'notifs_freq': request.user.notifs_freq.name,
        })
Ejemplo n.º 12
0
def campaign(request, id, action, api_format_ext):
	# get the object, make sure it is for the right brand that the user is viewing
	campaign = get_object_or_404(Campaign, id=id, brand=get_branding(request)['BRAND_INDEX'])

	# redirect to canonical URL if slug does not match
	# (pass along any query string variables like utm_campaign; when
	# a .json page is requested, the canonical path omits the slug)
	if not api_format_ext:
		canonical_path = campaign.get_absolute_url() + (api_format_ext or "")
	else:
		canonical_path = "/a/%d%s" % (campaign.id, api_format_ext)
	if action:
		canonical_path += "/" + action
	qs = (("?"+request.META['QUERY_STRING']) if request.META['QUERY_STRING'] else "")
	if request.path != canonical_path:
		@anonymous_view
		def redirector(request):
			return redirect(canonical_path+qs)
		return redirector(request)

	# The rest of this view is handled in the next two functions.
	if action is None:
		f = campaign_show
	elif api_format_ext is not None:
		raise Http404()
	elif action == "contribute":
		f = campaign_action_trigger
	else:
		raise Http404()

	# Cache?
	if campaign.status == CampaignStatus.Draft:
		# When a campaign is in draft status, we won't
		# cache the output to allow the user editing the
		# campaign's settings to reload the page to see
		# updated settings.
		pass
	else:
		# As soon as the campaign exits draft status we'll
		# mark the response as cachable so that the http
		# layer strongly caches the output.
		pass # f = anonymous_view(f)

	return f(request, campaign, api_format_ext == ".json")
Ejemplo n.º 13
0
def render_pledge_template(request, pledge, campaign, show_long_title=False, response_page=False):
	# Get the user's pledges, if any, on any trigger tied to this campaign.
	import django.template
	template = django.template.loader.get_template("contrib/contrib.html")
	
	ctx = {
		"response_page": response_page,
		"show_long_title": show_long_title,
		"pledge": pledge,
		"campaign": campaign,
		"execution": PledgeExecution.objects.filter(pledge=pledge).first(),
		"contribs": sorted(Contribution.objects.filter(pledge_execution__pledge=pledge).select_related("action", "recipient"), key=lambda c : (c.recipient_type.value, c.action.name_sort)),
		"share_url": request.build_absolute_uri(pledge.via_campaign.get_short_url()),
	}

	from itfsite.middleware import get_branding
	ctx.update(get_branding(request))
	
	return template.render(ctx)
Ejemplo n.º 14
0
def user_home(request):
	from contrib.models import Pledge, PledgeStatus

	# Get the user's actions that took place on the brand site that the user is actually on.
	brand_filter = { "via_campaign__brand": get_branding(request)['BRAND_INDEX'] }
	pledges = Pledge.objects.filter(user=request.user, **brand_filter).prefetch_related()
	actions = list(pledges)
	actions.sort(key = lambda obj : obj.created, reverse=True)
	
	# Get the user's total amount of open pledges, i.e. their total possible
	# future credit card charges / campaign contributions.
	open_pledges = pledges.filter(status=PledgeStatus.Open)
	if len(open_pledges) == 0:
		total_pledged = 0.0
	else:
		total_pledged = open_pledges.aggregate(total_pledged=Sum('amount'))['total_pledged']

	# Get the user's total amount of executed campaign contributions.
	total_contribs = pledges.filter(status=PledgeStatus.Executed)
	if len(total_contribs) == 0:
		total_contribs = 0.0
	else:
		total_contribs = total_contribs.aggregate(total_contribs=Sum('execution__charged'))['total_contribs']

	# Get the user's distinct ContributorInfo objects on *open* Pledges,
	# indicating future submitted info.
	if len(open_pledges) == 0:
		profiles = []
	else:
		profiles = set(p.profile for p in open_pledges)

	return render(request, "itfsite/user_home.html", {
		'actions': actions,

		'profiles': profiles,

		'total_pledged': total_pledged,
		'total_contribs': total_contribs,

		'notifs_freq': request.user.notifs_freq.name,
		})
Ejemplo n.º 15
0
def homepage(request):
    # The site homepage.

    # What campaigns *can* we show (logically)? Open campaigns for the brand we're looking at.
    open_campaigns = Campaign.objects.filter(
        status=CampaignStatus.Open, brand=get_branding(request)['BRAND_INDEX'])

    # How many to show?
    count = 12 if not settings.DEBUG else 100

    # Actually show recent campaigns (with some activity) + top performing campaigns.
    #
    # To efficiently query top performing campaigns we order by the sum of total_pledged (which only contains
    # Pledges made prior to trigger execution) and total_contributions (which only exists after the trigger
    # has been executed), since we don't have a field that just counts a simple total (ugh).
    open_campaigns = open_campaigns\
     .annotate(total=Sum('contrib_triggers__total_pledged')+Sum('contrib_triggers__execution__total_contributions'))\
     .exclude(total=None) # no Trigger associated with the Campaign
    open_campaigns = set(  # uniqify
        c for c in list(open_campaigns.order_by('-created')[0:count]) +
        list(open_campaigns.order_by("-total")[0:count]) if c.total > 0)
    if len(open_campaigns) > 0:
        # Order by a mix of recency and popularity. Prefer recency a bit.
        from math import sqrt
        newest = max(c.created for c in open_campaigns)
        oldest = min(c.created for c in open_campaigns)
        max_t = max(float(getattr(c, 'total', 0))
                    for c in open_campaigns) or 1.0  # Decimal => float
        open_campaigns = sorted(
            open_campaigns,
            key=lambda campaign: 1.1 - 1.1 *
            (newest - campaign.created).total_seconds() / (
                (newest - oldest).total_seconds() or 1) + sqrt(
                    float(getattr(campaign, 'total', 0)) / max_t),
            reverse=True)[0:count]

    return render2(request, "itfsite/homepage.html", {
        "open_campaigns": open_campaigns,
    })
Ejemplo n.º 16
0
def homepage(request):
	# The site homepage.

	# What campaigns *can* we show (logically)? Open campaigns for the brand we're looking at.
	open_campaigns = Campaign.objects.filter(status=CampaignStatus.Open, brand=get_branding(request)['BRAND_INDEX'])

	# How many to show?
	count = 12 if not settings.DEBUG else 100

	# Actually show recent campaigns (with some activity) + top performing campaigns.
	#
	# To efficiently query top performing campaigns we order by the sum of total_pledged (which only contains
	# Pledges made prior to trigger execution) and total_contributions (which only exists after the trigger
	# has been executed), since we don't have a field that just counts a simple total (ugh).
	open_campaigns = open_campaigns\
		.annotate(total=Sum('contrib_triggers__total_pledged')+Sum('contrib_triggers__execution__total_contributions'))\
		.exclude(total=None) # no Trigger associated with the Campaign
	open_campaigns = set( # uniqify
		c for c in 
		  list(open_campaigns.order_by('-created')[0:count])
		+ list(open_campaigns.order_by("-total")[0:count])
		if c.total > 0
		)
	if len(open_campaigns) > 0:
		# Order by a mix of recency and popularity. Prefer recency a bit.
		from math import sqrt
		newest = max(c.created for c in open_campaigns)
		oldest = min(c.created for c in open_campaigns)
		max_t = max(float(getattr(c, 'total', 0)) for c in open_campaigns) or 1.0 # Decimal => float
		open_campaigns = sorted(open_campaigns, key = lambda campaign:
			    1.1 - 1.1*(newest-campaign.created).total_seconds()/((newest-oldest).total_seconds() or 1)
			  + sqrt(float(getattr(campaign, 'total', 0)) / max_t)
			, reverse=True)[0:count]

	return render2(request, "itfsite/homepage.html", {
		"open_campaigns": open_campaigns,
	})
Ejemplo n.º 17
0
def campaign_show(request, campaign, is_json_api):
    # What Trigger and TriggerCustomization should we show?
    trigger, tcust = campaign.get_active_trigger()

    if trigger:
        outcome_strings = (tcust or trigger).outcome_strings()
        for i, os in enumerate(outcome_strings):
            os["id"] = i
    else:
        outcome_strings = []

    # for .json calls, just return data in JSON format
    if is_json_api:
        from .utils import json_response, serialize_obj, mergedicts
        brand = get_branding(request)
        return json_response({
            "site": {
                "name": brand["SITE_NAME"],
                "link": brand["ROOT_URL"],
                "logo": {
                    "w500":
                    brand["ROOT_URL"] + "/static/branding/" +
                    brand["BRAND_ID"] + "/logo.png",
                }
            },
            "campaign":
            mergedicts(
                serialize_obj(campaign,
                              keys=("id", "created", "updated", "title",
                                    "headline", "subhead", "body_text"),
                              render_text_map={
                                  "subhead": "subhead_format",
                                  "body_text": "body_format"
                              }),
                {
                    "link":
                    request.build_absolute_uri(campaign.get_absolute_url()),
                }),
            "trigger":
            mergedicts(
                serialize_obj(
                    trigger,
                    keys=("id", "created", "updated", "title", "description"),
                    render_text_map={"description": "description_format"}), {
                        "type":
                        trigger.trigger_type.title,
                        "outcomes":
                        outcome_strings,
                        "strings":
                        trigger.trigger_type.strings,
                        "max_split":
                        trigger.max_split(),
                        "desired_outcome":
                        outcome_strings[tcust.outcome] if tcust else None,
                    }) if trigger else None,
        })

    try:
        pref_outcome = int(request.GET["outcome"])
        if pref_outcome < 0 or pref_outcome >= len(outcome_strings):
            raise ValueError()
    except:
        pref_outcome = -1  # it's hard to distinguish 0 from None in templates

    # render page

    splash_image_qs = ""
    try:
        splash_image_qs += "&blur=" + (
            "1" if campaign.extra["style"]["splash"]["blur"] else "")
    except:
        pass
    try:
        splash_image_qs += "&brightness=" + str(
            campaign.extra["style"]["splash"]["brightness"] or "")
    except:
        pass

    # a/b testing
    import random
    experimental_condition = random.choice([1])

    return render(
        request,
        "itfsite/campaign_exp%d.html" % experimental_condition,
        {
            "campaign": campaign,
            "splash_image_qs": splash_image_qs,

            # for contrib.Trigger actions
            "trigger": trigger,
            "tcust": tcust,
            "trigger_outcome_strings": outcome_strings,
            "pref_outcome": pref_outcome,

            # for a/b testing
            "experiment": experimental_condition,
        })
Ejemplo n.º 18
0
def user_contribution_details(request):
    from contrib.models import PledgeExecution

    # Assemble a table of all line-item transactions.
    items = []

    # Contributions.
    brand = get_branding(
        request
    )  # only looking at contributions made on the site the user is looking at
    from contrib.models import Contribution
    contribs = Contribution.objects.filter(
     pledge_execution__pledge__user=request.user,
     pledge_execution__pledge__via_campaign__brand=brand['BRAND_INDEX'])\
     .select_related('pledge_execution', 'recipient', 'action', 'pledge_execution__trigger_execution__trigger')

    def contrib_line_item(c):
        return {
            'when':
            c.pledge_execution.created,
            'amount':
            c.amount,
            'recipient':
            c.name_long(),
            'trigger':
            c.pledge_execution.trigger_execution.trigger,
            'campaign':
            c.pledge_execution.pledge.via_campaign,
            'sort':
            (c.pledge_execution.created, 1, c.recipient.is_challenger, c.id),
        }

    items.extend([contrib_line_item(c) for c in contribs])

    # Fees.
    def fees_line_item(p):
        return {
            'when': p.created,
            'amount': p.fees,
            'recipient': '%s fees' % brand['SITE_NAME'],
            'trigger': p.trigger_execution.trigger,
            'campaign': p.pledge.via_campaign,
            'sort': (p.created, 0),
        }
    items.extend([fees_line_item(p) for p in PledgeExecution.objects.filter(
     pledge__user=request.user,
     pledge__via_campaign__brand=brand['BRAND_INDEX'])\
     .select_related('trigger_execution__trigger')])

    # Sort all together.
    items.sort(key=lambda x: x['sort'], reverse=True)

    if request.method == 'GET':
        # GET => HTML
        return render(request, "itfsite/user_contrib_details.html", {
            'items': items,
        })
    else:
        # POST => CSV
        from django.http import HttpResponse
        import csv
        from io import StringIO
        buf = StringIO()
        writer = csv.writer(buf)
        writer.writerow(['date', 'amount', 'recipient', 'action', 'link'])
        for item in items:
            writer.writerow([
                item['when'].isoformat(),
                item['amount'],
                item['recipient'],
                item['campaign'].title,
                item['campaign'].get_short_url(),
            ])
        buf = buf.getvalue().encode('utf8')

        if True:
            resp = HttpResponse(buf, content_type="text/csv")
            resp[
                'Content-Disposition'] = 'attachment; filename="contributions.csv"'
        else:
            resp = HttpResponse(buf, content_type="text/plain")
            resp['Content-Disposition'] = 'inline'
        resp["Content-Length"] = len(buf)
        return resp
Ejemplo n.º 19
0
def user_contribution_details(request):
	from contrib.models import PledgeExecution

	# Assemble a table of all line-item transactions.
	items = []

	# Contributions.
	brand = get_branding(request) # only looking at contributions made on the site the user is looking at
	from contrib.models import Contribution
	contribs = Contribution.objects.filter(
		pledge_execution__pledge__user=request.user,
		pledge_execution__pledge__via_campaign__brand=brand['BRAND_INDEX'])\
		.select_related('pledge_execution', 'recipient', 'action', 'pledge_execution__trigger_execution__trigger')
	def contrib_line_item(c):
		return {
			'when': c.pledge_execution.created,
			'amount': c.amount,
			'recipient': c.name_long(),
			'trigger': c.pledge_execution.trigger_execution.trigger,
			'campaign': c.pledge_execution.pledge.via_campaign,
			'sort': (c.pledge_execution.created, 1, c.recipient.is_challenger, c.id),
		}
	items.extend([contrib_line_item(c) for c in contribs])

	# Fees.
	def fees_line_item(p):
		return {
			'when': p.created,
			'amount': p.fees,
			'recipient': '%s fees' % brand['SITE_NAME'],
			'trigger': p.trigger_execution.trigger,
			'campaign': p.pledge.via_campaign,
			'sort': (p.created, 0),
		}
	items.extend([fees_line_item(p) for p in PledgeExecution.objects.filter(
		pledge__user=request.user,
		pledge__via_campaign__brand=brand['BRAND_INDEX'])\
		.select_related('trigger_execution__trigger')])

	# Sort all together.
	items.sort(key = lambda x : x['sort'], reverse=True)

	if request.method == 'GET':
		# GET => HTML
		return render(request, "itfsite/user_contrib_details.html", {
			'items': items,
			})
	else:
		# POST => CSV
		from django.http import HttpResponse
		import csv
		from io import StringIO
		buf = StringIO()
		writer = csv.writer(buf)
		writer.writerow(['date', 'amount', 'recipient', 'action', 'link'])
		for item in items:
			writer.writerow([
				item['when'].isoformat(),
				item['amount'],
				item['recipient'],
				item['campaign'].title,
				item['campaign'].get_short_url(),
				])
		buf = buf.getvalue().encode('utf8')

		if True:
			resp = HttpResponse(buf, content_type="text/csv")
			resp['Content-Disposition'] = 'attachment; filename="contributions.csv"'
		else:
			resp = HttpResponse(buf, content_type="text/plain")
			resp['Content-Disposition'] = 'inline'
		resp["Content-Length"] = len(buf)
		return resp
Ejemplo n.º 20
0
def campaign_show(request, campaign, is_json_api):
	# What Trigger and TriggerCustomization should we show?
	trigger, tcust = campaign.get_active_trigger()

	if trigger:
		outcome_strings = (tcust or trigger).outcome_strings()
		for i, os in enumerate(outcome_strings): os["id"] = i
	else:
		outcome_strings = []

	# for .json calls, just return data in JSON format
	if is_json_api:
		from .utils import json_response, serialize_obj, mergedicts
		brand = get_branding(request)
		return json_response({
			"site": {
				"name": brand["SITE_NAME"],
				"link": brand["ROOT_URL"],
				"logo": {
					"w500": brand["ROOT_URL"] + "/static/branding/" + brand["BRAND_ID"] + "/logo.png",
				}
			},
			"campaign": mergedicts(
				serialize_obj(campaign, keys=("id", "created", "updated", "title", "headline", "subhead", "body_text"),
						render_text_map={ "subhead": "subhead_format", "body_text": "body_format" }),
				{
					"link": request.build_absolute_uri(campaign.get_absolute_url()),
				}),
			"trigger": mergedicts(
				serialize_obj(trigger, keys=("id", "created", "updated", "title", "description"),
						render_text_map={ "description": "description_format" }),
				{
					"type": trigger.trigger_type.title,
					"outcomes": outcome_strings,
					"strings": trigger.trigger_type.strings,
					"max_split": trigger.max_split(),
					"desired_outcome": outcome_strings[tcust.outcome] if tcust else None,
				}) if trigger else None,
			})

	try:
		pref_outcome = int(request.GET["outcome"])
		if pref_outcome < 0 or pref_outcome >= len(outcome_strings): raise ValueError()
	except:
		pref_outcome = -1 # it's hard to distinguish 0 from None in templates

	# render page

	splash_image_qs = ""
	try:
		splash_image_qs += "&blur=" + ("1" if campaign.extra["style"]["splash"]["blur"] else "")
	except:
		pass
	try:
		splash_image_qs += "&brightness=" + str(campaign.extra["style"]["splash"]["brightness"] or "")
	except:
		pass

	# a/b testing
	import random
	experimental_condition = random.choice([1])

	return render(request, "itfsite/campaign_exp%d.html" % experimental_condition, {
		"campaign": campaign,
		"splash_image_qs": splash_image_qs,

		# for contrib.Trigger actions
		"trigger": trigger,
		"tcust": tcust,
		"trigger_outcome_strings": outcome_strings,
		"pref_outcome": pref_outcome,

		# for a/b testing
		"experiment": experimental_condition,
		})