def adzerk_request(
    keywords, properties, user_id,
    num_placements=1,
    timeout=1.5,
    platform="desktop",
    is_refresh=False,
    referrer=None,
):
    placements = []
    divs = ["div%s" % i for i in xrange(num_placements)]
    subreddit = None

    if isinstance(c.site, Subreddit) and not c.default_sr:
        subreddit = c.site.name

    for div in divs:
        placement = {
          "divName": div,
          "networkId": g.az_selfserve_network_id,
          "siteId": g.az_selfserve_site_ids[platform],
          "adTypes": [LEADERBOARD_AD_TYPE],
          "eventIds": [EVENT_TYPE_UPVOTE, EVENT_TYPE_DOWNVOTE],
          "properties": properties,
        }

        if subreddit is not None:
            placement["properties"] = {
                "subreddit": subreddit,
            }

        placements.append(placement)

    keywords = [word.lower() for word in keywords]
    data = {
        "placements": placements,
        "keywords": keywords,
        "ip": request.ip,
        "enableBotFiltering": True,
        "includePricingData": True,
    }

    page_url = request.headers.get("referer", None)

    if page_url is not None:
        data["url"] = page_url

    if referrer is not None:
        data["referrer"] = referrer

    if user_id:
        data["user"] = {"key": user_id}

    url = 'https://%s/api/v2' % g.adzerk_engine_domain
    headers = {
        'content-type': 'application/json',
        'user-agent': request.headers.get('User-Agent'),
    }

    do_not_track = request.headers.get("DNT", None)

    if do_not_track and feature.is_enabled("adzerk_do_not_track"):
        headers["DNT"] = do_not_track

    timer = g.stats.get_timer("providers.adzerk")
    timer.start()

    for placement in placements:
        g.ad_events.ad_request(
            keywords=keywords,
            platform=platform,
            placement_name=placement["divName"],
            placement_types=placement["adTypes"],
            is_refresh=is_refresh,
            subreddit=c.site,
            request=request,
            context=c,
        )

    try:
        r = requests.post(url, data=json.dumps(data), headers=headers,
                          timeout=timeout)
    except (requests.exceptions.Timeout, requests.exceptions.SSLError):
        g.stats.simple_event('adzerk.request.timeout')
        return None
    except requests.exceptions.ConnectionError:
        g.stats.simple_event('adzerk.request.refused')
        return None
    except select.error:
        return None
    finally:
        timer.stop()

    errored = False

    try:
        response = adzerk_api.handle_response(r)
    except adzerk_api.AdzerkError:
        g.stats.simple_event('adzerk.request.badresponse')
        g.log.error('adzerk_request: bad response (%s) %r', r.status_code,
                    r.content)
        errored = True
    finally:
        # Temporarily log request data and response body,
        # sample at 1%
        if random.random() < g.live_config.get('ad_log_sample_rate', 0):
            g.log.info("ad_request [DNT=%s]: %s, ad_response: [%s] %s",
                do_not_track, json.dumps(data), r.status_code, r.text)

        if errored:
            return None



    decisions = response['decisions']

    if not decisions:
        return None

    placements_by_div = {placement["divName"]: placement
        for placement in placements}

    res = []
    for div in divs:
        decision = decisions[div]
        if not decision:
            continue

        placement = placements_by_div[div]
        ad_id = decision['adId']
        pricing = decision.get("pricing", {})
        revenue = pricing.get("revenue")
        rate_type_id = pricing.get("rateType")
        rate_type = RATE_TYPE_NAMES.get(rate_type_id, None)
        impression_url = decision.get("impressionUrl")
        impression_b64_data = UrlParser(impression_url).query_dict.get("e", "")
        impression_id, matched_keywords = None, []

        try:
            # fix padding and string encode
            impression_b64_data = str(
                impression_b64_data +
                ("=" * (len(impression_b64_data) % 4))
            )
            impression_data = json.loads(
                base64.urlsafe_b64decode(impression_b64_data),
                strict=False,
            )
        except UnicodeDecodeError:
            g.log.info("unable to decode impression data: %s", impression_b64_data)
            impression_data = None
        except TypeError, ValueError:
            impression_data = None

        if impression_data is not None:
            impression_id = impression_data.get("di")
            matched_keywords = impression_data.get("mk")

        if matched_keywords:
            matched_keywords = matched_keywords.split(",")


        # adserver ads are not reddit links, we return the body
        if decision['campaignId'] in g.adserver_campaign_ids:
            g.ad_events.ad_response(
                keywords=keywords,
                platform=platform,
                placement_name=div,
                placement_types=placement["adTypes"],
                ad_id=ad_id,
                impression_id=impression_id,
                matched_keywords=matched_keywords,
                rate_type=rate_type,
                clearing_price=revenue,
                subreddit=c.site,
                request=request,
                context=c,
            )

            return AdserverResponse(decision['contents'][0]['body'])

        adzerk_flight_id = decision['flightId']
        imp_pixel = decision['impressionUrl']
        click_url = decision['clickUrl']
        events_by_id = {event["id"]: event["url"] for event in decision["events"]}
        upvote_pixel = events_by_id[EVENT_TYPE_UPVOTE]
        downvote_pixel = events_by_id[EVENT_TYPE_DOWNVOTE]

        campaign_fullname = PromoCampaignByFlightIdCache.get(adzerk_flight_id)
        contents = decision['contents'][0]
        body = json.loads(contents['body'])
        link_fullname = body['link']
        target = body['target']
        priority = None
        priority_id = body.get('priorityId', None)
        ecpm = body.get('ecpm', None)
        moat_query = body.get('moatQuery', None)

        if priority_id is not None:
            try:
                priority_id = int(priority_id)
            except ValueError:
                pass

            for k, v in g.az_selfserve_priorities.iteritems():
                if priority_id == v:
                    priority = k

        g.ad_events.ad_response(
            keywords=keywords,
            platform=platform,
            placement_name=div,
            placement_types=placement["adTypes"],
            ad_id=ad_id,
            impression_id=impression_id,
            matched_keywords=matched_keywords,
            rate_type=rate_type,
            clearing_price=revenue,
            subreddit=c.site,
            link_fullname=link_fullname,
            campaign_fullname=campaign_fullname,
            priority=priority,
            ecpm=ecpm,
            request=request,
            context=c,
        )

        if not campaign_fullname:
            link = Link._by_fullname(link_fullname, data=True, stale=True)

            if promote.is_external(link):
                campaign_fullname = promote.EXTERNAL_CAMPAIGN
            else:
                adzerk_campaign_id = decision['campaignId']

                g.stats.simple_event('adzerk.request.orphaned_flight')
                g.log.error('adzerk_request: couldn\'t find campaign for flight (az campaign: %s, flight: %s)',
                    adzerk_campaign_id, adzerk_flight_id)

                # deactivate the flight, it will be reactivated if a
                # valid campaign actually exists
                deactivate_orphaned_flight(adzerk_flight_id)
                continue

        res.append(AdzerkResponse(
            link=link_fullname,
            campaign=campaign_fullname,
            target=target,
            ecpm=ecpm,
            priority=priority,
            moat_query=moat_query,
            imp_pixel=imp_pixel,
            click_url=click_url,
            upvote_pixel=upvote_pixel,
            downvote_pixel=downvote_pixel,
        ))
def adzerk_request(keywords, num_placements=1, timeout=1.5, mobile_web=False):
    placements = []
    divs = ["div%s" % i for i in xrange(num_placements)]

    if mobile_web:
        site_id = g.az_selfserve_mobile_web_site_id
    else:
        site_id = g.az_selfserve_site_id

    for div in divs:
        placement = {
          "divName": div,
          "networkId": g.az_selfserve_network_id,
          "siteId": site_id,
          "adTypes": [g.az_selfserve_ad_type]
        }
        placements.append(placement)

    data = {
        "placements": placements,
        "keywords": [word.lower() for word in keywords],
        "ip": request.ip,
    }

    url = 'https://engine.adzerk.net/api/v2'
    headers = {
        'content-type': 'application/json',
        'user-agent': request.headers.get('User-Agent'),
    }

    timer = g.stats.get_timer("providers.adzerk")
    timer.start()

    try:
        r = requests.post(url, data=json.dumps(data), headers=headers,
                          timeout=timeout)
    except (requests.exceptions.Timeout, requests.exceptions.SSLError):
        g.stats.simple_event('adzerk.request.timeout')
        return None
    except requests.exceptions.ConnectionError:
        g.stats.simple_event('adzerk.request.refused')
        return None
    finally:
        timer.stop()

    try:
        response = adzerk_api.handle_response(r)
    except adzerk_api.AdzerkError:
        g.stats.simple_event('adzerk.request.badresponse')
        g.log.error('adzerk_request: bad response (%s) %r', r.status_code,
                    r.content)
        return None

    decisions = response['decisions']

    if not decisions:
        return None

    res = []
    for div in divs:
        decision = decisions[div]
        if not decision:
            continue

        imp_pixel = decision['impressionUrl']
        click_url = decision['clickUrl']
        body = json.loads(decision['contents'][0]['body'])
        campaign = body['campaign']
        link = body['link']
        target = body['target']
        res.append(AdzerkResponse(link, campaign, target, imp_pixel, click_url))
    return res
def adzerk_request(keywords, uid, num_placements=1, timeout=1.5,
                   mobile_web=False):
    placements = []
    divs = ["div%s" % i for i in xrange(num_placements)]

    if mobile_web:
        site_id = g.az_selfserve_mobile_web_site_id
    else:
        site_id = g.az_selfserve_site_id

    for div in divs:
        placement = {
          "divName": div,
          "networkId": g.az_selfserve_network_id,
          "siteId": site_id,
          "adTypes": [LEADERBOARD_AD_TYPE]
        }
        placements.append(placement)

    data = {
        "placements": placements,
        "keywords": [word.lower() for word in keywords],
        "ip": request.ip,
    }

    if uid:
        data["user"] = {"key": uid}

    url = 'https://engine.adzerk.net/api/v2'
    headers = {
        'content-type': 'application/json',
        'user-agent': request.headers.get('User-Agent'),
    }

    timer = g.stats.get_timer("providers.adzerk")
    timer.start()

    try:
        r = requests.post(url, data=json.dumps(data), headers=headers,
                          timeout=timeout)
    except (requests.exceptions.Timeout, requests.exceptions.SSLError):
        g.stats.simple_event('adzerk.request.timeout')
        return None
    except requests.exceptions.ConnectionError:
        g.stats.simple_event('adzerk.request.refused')
        return None
    finally:
        timer.stop()

    try:
        response = adzerk_api.handle_response(r)
    except adzerk_api.AdzerkError:
        g.stats.simple_event('adzerk.request.badresponse')
        g.log.error('adzerk_request: bad response (%s) %r', r.status_code,
                    r.content)
        return None

    decisions = response['decisions']

    if not decisions:
        return None

    res = []
    for div in divs:
        decision = decisions[div]
        if not decision:
            continue

        # adserver ads are not reddit links, we return the body
        if decision['campaignId'] in g.adserver_campaign_ids:
            return AdserverResponse(decision['contents'][0]['body'])

        adzerk_campaign_id = decision['campaignId']
        adzerk_flight_id = decision['flightId']
        imp_pixel = decision['impressionUrl']
        click_url = decision['clickUrl']

        campaign = PromoCampaignByFlightIdCache.get(adzerk_flight_id)

        if not campaign:
            g.stats.simple_event('adzerk.request.orphaned_flight')
            g.log.error('adzerk_request: couldn\'t find campaign for flight (az campaign: %s, flight: %s)',
                adzerk_campaign_id, adzerk_flight_id)

            # deactivate the flight, it will be reactivated if a
            # valid campaign actually exists
            deactivate_orphaned_flight(adzerk_flight_id)
            continue

        body = json.loads(decision['contents'][0]['body'])
        link = body['link']
        target = body['target']
        res.append(AdzerkResponse(link, campaign, target, imp_pixel, click_url))
    return res
def adzerk_request(
    keywords, properties, user_id,
    num_placements=1,
    timeout=1.5,
    platform="desktop",
    is_refresh=False,
):
    placements = []
    divs = ["div%s" % i for i in xrange(num_placements)]

    for div in divs:
        placement = {
          "divName": div,
          "networkId": g.az_selfserve_network_id,
          "siteId": g.az_selfserve_site_ids[platform],
          "adTypes": [LEADERBOARD_AD_TYPE],
          "eventIds": [EVENT_TYPE_UPVOTE, EVENT_TYPE_DOWNVOTE],
          "properties": properties,
        }
        placements.append(placement)

    keywords = [word.lower() for word in keywords]
    data = {
        "placements": placements,
        "keywords": keywords,
        "ip": request.ip,
        "enableBotFiltering": True,
    }

    referrer = request.headers.get("referer", None)

    if referrer:
        data["referrer"] = referrer

    if user_id:
        data["user"] = {"key": user_id}

    url = 'https://%s/api/v2' % g.adzerk_engine_domain
    headers = {
        'content-type': 'application/json',
        'user-agent': request.headers.get('User-Agent'),
    }

    do_not_track = request.headers.get("DNT", None)

    if do_not_track and feature.is_enabled("adzerk_do_not_track"):
        headers["DNT"] = do_not_track

    timer = g.stats.get_timer("providers.adzerk")
    timer.start()

    for placement in placements:
        g.ad_events.ad_request(
            keywords=keywords,
            platform=platform,
            placement_name=placement["divName"],
            placement_types=placement["adTypes"],
            is_refresh=is_refresh,
            subreddit=c.site,
            request=request,
            context=c,
        )

    try:
        r = requests.post(url, data=json.dumps(data), headers=headers,
                          timeout=timeout)
    except (requests.exceptions.Timeout, requests.exceptions.SSLError):
        g.stats.simple_event('adzerk.request.timeout')
        return None
    except requests.exceptions.ConnectionError:
        g.stats.simple_event('adzerk.request.refused')
        return None
    finally:
        timer.stop()

    errored = False

    try:
        response = adzerk_api.handle_response(r)
    except adzerk_api.AdzerkError:
        g.stats.simple_event('adzerk.request.badresponse')
        g.log.error('adzerk_request: bad response (%s) %r', r.status_code,
                    r.content)
        errored = True
    finally:
        # Temporarily log request data and response body,
        # sample at 1%
        if random.random() < g.live_config.get('ad_log_sample_rate', 0):
            g.log.info("ad_request [DNT=%s]: %s, ad_response: [%s] %s",
                do_not_track, json.dumps(data), r.status_code, r.text)

        if errored:
            return None



    decisions = response['decisions']

    if not decisions:
        return None

    placements_by_div = {placement["divName"]: placement
        for placement in placements}

    res = []
    for div in divs:
        decision = decisions[div]
        if not decision:
            continue

        placement = placements_by_div[div]
        ad_id = decision['adId']

        # adserver ads are not reddit links, we return the body
        if decision['campaignId'] in g.adserver_campaign_ids:
            g.ad_events.ad_response(
                keywords=keywords,
                platform=platform,
                placement_name=div,
                placement_types=placement["adTypes"],
                ad_id=ad_id,
                subreddit=c.site,
                request=request,
                context=c,
            )

            return AdserverResponse(decision['contents'][0]['body'])

        adzerk_flight_id = decision['flightId']
        imp_pixel = decision['impressionUrl']
        click_url = decision['clickUrl']
        events_by_id = {event["id"]: event["url"] for event in decision["events"]}
        upvote_pixel = events_by_id[EVENT_TYPE_UPVOTE]
        downvote_pixel = events_by_id[EVENT_TYPE_DOWNVOTE]

        campaign_fullname = PromoCampaignByFlightIdCache.get(adzerk_flight_id)
        contents = decision['contents'][0]
        body = json.loads(contents['body'])
        link_fullname = body['link']
        target = body['target']
        priority = None
        priority_id = body.get('priorityId', None)
        ecpm = body.get('ecpm', None)

        if priority_id:
            priority = PRIORITIES_BY_ID.get(priority_id, "unknown (%s)" % priority_id)

        g.ad_events.ad_response(
            keywords=keywords,
            platform=platform,
            placement_name=div,
            placement_types=placement["adTypes"],
            ad_id=ad_id,
            subreddit=c.site,
            link_fullname=link_fullname,
            campaign_fullname=campaign_fullname,
            priority=priority,
            ecpm=ecpm,
            request=request,
            context=c,
        )

        if not campaign_fullname:
            link = Link._by_fullname(link_fullname, data=True, stale=True)

            if promote.is_external(link):
                campaign_fullname = promote.EXTERNAL_CAMPAIGN
            else:
                adzerk_campaign_id = decision['campaignId']

                g.stats.simple_event('adzerk.request.orphaned_flight')
                g.log.error('adzerk_request: couldn\'t find campaign for flight (az campaign: %s, flight: %s)',
                    adzerk_campaign_id, adzerk_flight_id)

                # deactivate the flight, it will be reactivated if a
                # valid campaign actually exists
                deactivate_orphaned_flight(adzerk_flight_id)
                continue

        res.append(AdzerkResponse(
            link=link_fullname,
            campaign=campaign_fullname,
            target=target,
            ecpm=ecpm,
            priority=priority,
            imp_pixel=imp_pixel,
            click_url=click_url,
            upvote_pixel=upvote_pixel,
            downvote_pixel=downvote_pixel,
        ))
    return res
def adzerk_request(keywords, uid, num_placements=1, timeout=1.5,
                   platform="desktop"):
    placements = []
    divs = ["div%s" % i for i in xrange(num_placements)]

    for div in divs:
        placement = {
          "divName": div,
          "networkId": g.az_selfserve_network_id,
          "siteId": g.az_selfserve_site_ids[platform],
          "adTypes": [LEADERBOARD_AD_TYPE],
          "eventIds": [EVENT_TYPE_UPVOTE, EVENT_TYPE_DOWNVOTE],
        }
        placements.append(placement)

    data = {
        "placements": placements,
        "keywords": [word.lower() for word in keywords],
        "ip": request.ip,
    }

    referrer = request.headers.get("referer", None)

    if referrer:
        data["referrer"] = referrer

    if uid:
        data["user"] = {"key": uid}

    url = 'https://%s/api/v2' % g.adzerk_engine_domain
    headers = {
        'content-type': 'application/json',
        'user-agent': request.headers.get('User-Agent'),
    }

    do_not_track = request.headers.get("DNT", None)

    if do_not_track and feature.is_enabled("adzerk_do_not_track"):
        headers["DNT"] = do_not_track

    timer = g.stats.get_timer("providers.adzerk")
    timer.start()

    try:
        r = requests.post(url, data=json.dumps(data), headers=headers,
                          timeout=timeout)
    except (requests.exceptions.Timeout, requests.exceptions.SSLError):
        g.stats.simple_event('adzerk.request.timeout')
        return None
    except requests.exceptions.ConnectionError:
        g.stats.simple_event('adzerk.request.refused')
        return None
    finally:
        timer.stop()

    try:
        response = adzerk_api.handle_response(r)
    except adzerk_api.AdzerkError:
        g.stats.simple_event('adzerk.request.badresponse')
        g.log.error('adzerk_request: bad response (%s) %r', r.status_code,
                    r.content)
        return None

    decisions = response['decisions']

    if not decisions:
        return None

    res = []
    for div in divs:
        decision = decisions[div]
        if not decision:
            continue

        # adserver ads are not reddit links, we return the body
        if decision['campaignId'] in g.adserver_campaign_ids:
            return AdserverResponse(decision['contents'][0]['body'])

        adzerk_campaign_id = decision['campaignId']
        adzerk_flight_id = decision['flightId']
        imp_pixel = decision['impressionUrl']
        click_url = decision['clickUrl']
        events_by_id = {event["id"]: event["url"] for event in decision["events"]}
        upvote_pixel = events_by_id[EVENT_TYPE_UPVOTE]
        downvote_pixel = events_by_id[EVENT_TYPE_DOWNVOTE]

        campaign = PromoCampaignByFlightIdCache.get(adzerk_flight_id)

        if not campaign:
            g.stats.simple_event('adzerk.request.orphaned_flight')
            g.log.error('adzerk_request: couldn\'t find campaign for flight (az campaign: %s, flight: %s)',
                adzerk_campaign_id, adzerk_flight_id)

            # deactivate the flight, it will be reactivated if a
            # valid campaign actually exists
            deactivate_orphaned_flight(adzerk_flight_id)
            continue

        body = json.loads(decision['contents'][0]['body'])
        link = body['link']
        target = body['target']
        res.append(AdzerkResponse(
            link=link,
            campaign=campaign,
            target=target,
            imp_pixel=imp_pixel,
            click_url=click_url,
            upvote_pixel=upvote_pixel,
            downvote_pixel=downvote_pixel,
        ))
    return res
Exemple #6
0
def adzerk_request(keywords, num_placements=1, timeout=1.5, mobile_web=False):
    placements = []
    divs = ["div%s" % i for i in xrange(num_placements)]

    if mobile_web:
        site_id = g.az_selfserve_mobile_web_site_id
    else:
        site_id = g.az_selfserve_site_id

    for div in divs:
        placement = {
            "divName": div,
            "networkId": g.az_selfserve_network_id,
            "siteId": site_id,
            "adTypes": [g.az_selfserve_ad_type]
        }
        placements.append(placement)

    data = {
        "placements": placements,
        "keywords": [word.lower() for word in keywords],
        "ip": request.ip,
    }

    url = 'https://engine.adzerk.net/api/v2'
    headers = {
        'content-type': 'application/json',
        'user-agent': request.headers.get('User-Agent'),
    }

    timer = g.stats.get_timer("providers.adzerk")
    timer.start()

    try:
        r = requests.post(url,
                          data=json.dumps(data),
                          headers=headers,
                          timeout=timeout)
    except (requests.exceptions.Timeout, requests.exceptions.SSLError):
        g.stats.simple_event('adzerk.request.timeout')
        return None
    except requests.exceptions.ConnectionError:
        g.stats.simple_event('adzerk.request.refused')
        return None
    finally:
        timer.stop()

    try:
        response = adzerk_api.handle_response(r)
    except adzerk_api.AdzerkError:
        g.stats.simple_event('adzerk.request.badresponse')
        g.log.error('adzerk_request: bad response (%s) %r', r.status_code,
                    r.content)
        return None

    decisions = response['decisions']

    if not decisions:
        return None

    res = []
    for div in divs:
        decision = decisions[div]
        if not decision:
            continue

        imp_pixel = decision['impressionUrl']
        click_url = decision['clickUrl']
        body = json.loads(decision['contents'][0]['body'])
        campaign = body['campaign']
        link = body['link']
        target = body['target']
        res.append(AdzerkResponse(link, campaign, target, imp_pixel,
                                  click_url))
    return res
Exemple #7
0
def adzerk_request(keywords,
                   uid,
                   num_placements=1,
                   timeout=1.5,
                   platform="desktop"):
    placements = []
    divs = ["div%s" % i for i in xrange(num_placements)]

    for div in divs:
        placement = {
            "divName": div,
            "networkId": g.az_selfserve_network_id,
            "siteId": g.az_selfserve_site_ids[platform],
            "adTypes": [LEADERBOARD_AD_TYPE],
            "eventIds": [EVENT_TYPE_UPVOTE, EVENT_TYPE_DOWNVOTE],
        }
        placements.append(placement)

    data = {
        "placements": placements,
        "keywords": [word.lower() for word in keywords],
        "ip": request.ip,
    }

    referrer = request.headers.get("referer", None)

    if referrer:
        data["referrer"] = referrer

    if uid:
        data["user"] = {"key": uid}

    url = 'https://%s/api/v2' % g.adzerk_engine_domain
    headers = {
        'content-type': 'application/json',
        'user-agent': request.headers.get('User-Agent'),
    }

    do_not_track = request.headers.get("DNT", None)

    if do_not_track and feature.is_enabled("adzerk_do_not_track"):
        headers["DNT"] = do_not_track

    timer = g.stats.get_timer("providers.adzerk")
    timer.start()

    try:
        r = requests.post(url,
                          data=json.dumps(data),
                          headers=headers,
                          timeout=timeout)
    except (requests.exceptions.Timeout, requests.exceptions.SSLError):
        g.stats.simple_event('adzerk.request.timeout')
        return None
    except requests.exceptions.ConnectionError:
        g.stats.simple_event('adzerk.request.refused')
        return None
    finally:
        timer.stop()

    try:
        response = adzerk_api.handle_response(r)
    except adzerk_api.AdzerkError:
        g.stats.simple_event('adzerk.request.badresponse')
        g.log.error('adzerk_request: bad response (%s) %r', r.status_code,
                    r.content)
        return None

    decisions = response['decisions']

    if not decisions:
        return None

    res = []
    for div in divs:
        decision = decisions[div]
        if not decision:
            continue

        # adserver ads are not reddit links, we return the body
        if decision['campaignId'] in g.adserver_campaign_ids:
            return AdserverResponse(decision['contents'][0]['body'])

        adzerk_campaign_id = decision['campaignId']
        adzerk_flight_id = decision['flightId']
        imp_pixel = decision['impressionUrl']
        click_url = decision['clickUrl']
        events_by_id = {
            event["id"]: event["url"]
            for event in decision["events"]
        }
        upvote_pixel = events_by_id[EVENT_TYPE_UPVOTE]
        downvote_pixel = events_by_id[EVENT_TYPE_DOWNVOTE]

        campaign = PromoCampaignByFlightIdCache.get(adzerk_flight_id)

        if not campaign:
            g.stats.simple_event('adzerk.request.orphaned_flight')
            g.log.error(
                'adzerk_request: couldn\'t find campaign for flight (az campaign: %s, flight: %s)',
                adzerk_campaign_id, adzerk_flight_id)

            # deactivate the flight, it will be reactivated if a
            # valid campaign actually exists
            deactivate_orphaned_flight(adzerk_flight_id)
            continue

        body = json.loads(decision['contents'][0]['body'])
        link = body['link']
        target = body['target']
        res.append(
            AdzerkResponse(
                link=link,
                campaign=campaign,
                target=target,
                imp_pixel=imp_pixel,
                click_url=click_url,
                upvote_pixel=upvote_pixel,
                downvote_pixel=downvote_pixel,
            ))
    return res