Created
October 11, 2018 17:09
-
-
Save evandandrea/0211ca01036b8fae178e23b4fd61e5bb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import requests | |
import urllib | |
import sys | |
import os | |
import argparse | |
import datetime | |
import json | |
ISO8601 = "%Y-%m-%dT%H:%M:%SZ" | |
def get_marketo_access_token(config): | |
url = urllib.parse.urljoin(config.marketo_root, '/identity/oauth/token') | |
params = { | |
'grant_type': 'client_credentials', | |
'client_id': config.marketo_client_id, | |
'client_secret': config.marketo_secret, | |
} | |
url += '?' + urllib.parse.urlencode(params) | |
response = requests.get(url) | |
response.raise_for_status() | |
return response.json()['access_token'] | |
def get_paging_token(config, token, since): | |
url = urllib.parse.urljoin( | |
config.marketo_root, | |
'/rest/v1/activities/pagingtoken.json' | |
) | |
params = { | |
'access_token': token, | |
'sinceDatetime': since.isoformat() + 'Z', | |
} | |
url += '?' + urllib.parse.urlencode(params) | |
response = requests.get(url) | |
response.raise_for_status() | |
return response.json()['nextPageToken'] | |
def get_activities(config, token, activity_type_ids, asset_ids, page_token): | |
url = urllib.parse.urljoin( | |
config.marketo_root, | |
'/rest/v1/activities.json' | |
) | |
params = { | |
'access_token': token, | |
'activityTypeIds': ','.join(activity_type_ids), | |
'assetIds': ','.join(asset_ids), | |
'nextPageToken': page_token, | |
} | |
response = requests.get(url + '?' + urllib.parse.urlencode(params)) | |
response.raise_for_status() | |
obj = response.json() | |
try: | |
results = obj['result'] | |
except KeyError: | |
results = [] | |
while True: | |
if obj['moreResult'] and obj['nextPageToken']: | |
params['nextPageToken'] = obj['nextPageToken'] | |
response = requests.get(url + '?' + urllib.parse.urlencode(params)) | |
response.raise_for_status() | |
obj = response.json() | |
try: | |
results += obj['result'] | |
except KeyError: | |
# https://nation.marketo.com/thread/45451-get-activities-doesnt-show-results | |
pass | |
else: | |
break | |
return results | |
def get_snap_objects(config, token, store_account_id): | |
params = { | |
'filterType': 'snapStoreAccountID', | |
'filterValues': store_account_id, | |
'access_token': token | |
} | |
url = config.marketo_root + '/rest/v1/customobjects/snap_c.json/?' | |
url = url + urllib.parse.urlencode(params) | |
response = requests.get(url) | |
return response.json()['result'] | |
def get_lead(config, token, lead_id, fields=None): | |
params = { | |
'access_token': token, | |
} | |
if fields: | |
params['fields'] = ','.join(fields) | |
url = config.marketo_root + '/rest/v1/lead/{}.json'.format(lead_id) | |
params = urllib.parse.urlencode(params) | |
response = requests.get(url + '?' + params) | |
return response.json()['result'][0] | |
def get_leads_with_activity_before_date(config, token, activity_type, activity_asset, page_token, date): | |
'''activity_type: The Marketo identifier for the type of activity. For | |
example, 10 is "Open Email". | |
activity_asset: The target of that activity. For example, 7099 is the | |
"Thanks for checking out Snapcraft" email. | |
page_token: A Marketo token specifically for pagination. | |
date: Activities ocurring after this date will be ignored. | |
''' | |
activity_type_ids = [activity_type] | |
asset_ids = [activity_asset] | |
leads = [] | |
for obj in get_activities(config, token, activity_type_ids, asset_ids, page_token): | |
activity_date = datetime.datetime.strptime(obj['activityDate'], ISO8601).date() | |
if activity_date <= date: | |
leads.append((obj['leadId'], activity_date)) | |
return leads | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser() | |
parser.add_argument('date', metavar='YYYY-MM-DD', nargs='?') | |
parser.add_argument('--marketo-root', required=True) | |
parser.add_argument('--marketo-secret', required=True) | |
parser.add_argument('--marketo-client-id', required=True) | |
config = parser.parse_args(sys.argv[1:]) | |
if config.date: | |
start = datetime.datetime.strptime(config.date, '%Y-%m-%d') | |
else: | |
start = datetime.date.today() - datetime.timedelta(days=1) | |
token = get_marketo_access_token(config) | |
two_weeks_prior = start - datetime.timedelta(days=14) | |
one_week_prior = start - datetime.timedelta(days=7) | |
page_token = get_paging_token(config, token, two_weeks_prior) | |
# Email 1 | |
# 7099: Thanks for checking out Snapcraft | |
leads = get_leads_with_activity_before_date( | |
config, token, '10', '7099', page_token, one_week_prior | |
) | |
succeeded = 0 | |
for lead_id, mail_date in leads: | |
lead = get_lead(config, token, lead_id, fields=['snapStoreAccountID']) | |
store_account_id = lead['snapStoreAccountID'] | |
snaps = get_snap_objects(config, token, store_account_id) | |
for snap in snaps: | |
created_at = snap['createdAt'] | |
created_date = datetime.datetime.strptime(created_at, ISO8601).date() | |
if created_date - mail_date <= datetime.timedelta(days=7): | |
succeeded += 1 | |
break | |
print('In the week starting {}:'.format(two_weeks_prior)) | |
msg = 'Read "Thanks for checking out Snapcraft": {}' | |
print(msg.format(len(leads))) | |
msg = 'Pushed a snap within 7 days of reading the mail: {} ({:.2f}%)' | |
if succeeded > 0: | |
percent = succeeded/len(leads)*100 | |
else: | |
percent = 0 | |
print(msg.format(succeeded, percent)) | |
# Email 2 | |
# 7103: Ready to reach a wider audience? | |
leads = get_leads_with_activity_before_date( | |
config, token, '10', '7103', page_token, one_week_prior | |
) | |
succeeded = 0 | |
for lead_id, mail_date in leads: | |
lead = get_lead(config, token, lead_id, fields=['snapStoreAccountID']) | |
store_account_id = lead['snapStoreAccountID'] | |
snaps = get_snap_objects(config, token, store_account_id) | |
for snap in snaps: | |
if snap['mostStableChannelReached'] == 'stable': | |
# FIXME this doesn't carry the date stable was reached. | |
# Could have happened at any time since. | |
# Could backfill from release history. | |
succeeded += 1 | |
break | |
print('In the week starting {}:'.format(two_weeks_prior)) | |
msg = 'Read "Ready to reach a wider audience?": {}' | |
print(msg.format(len(leads))) | |
msg = 'Released to stable within 7 days of reading the mail: {} ({:.2f}%)' | |
if succeeded > 0: | |
percent = succeeded/len(leads)*100 | |
else: | |
percent = 0 | |
print(msg.format(succeeded, percent)) | |
# Email 3 | |
# 7038: Make snap pop | |
leads = get_leads_with_activity_before_date( | |
config, token, '10', '7038', page_token, one_week_prior | |
) | |
succeeded = 0 | |
for lead_id, mail_date in leads: | |
lead = get_lead(config, token, lead_id, fields=['snapStoreAccountID']) | |
store_account_id = lead['snapStoreAccountID'] | |
snaps = get_snap_objects(config, token, store_account_id) | |
for snap in snaps: | |
if snap['hasCompleteListingDetails']: | |
# FIXME this doesn't carry the date stable was reached. | |
# Could have happened at any time since. | |
# Impossible to backfill; data not currently tracked. | |
succeeded += 1 | |
break | |
print('In the week starting {}:'.format(two_weeks_prior)) | |
msg = 'Read "Make snap pop": {}' | |
print(msg.format(len(leads))) | |
msg = 'Added details within 7 days of reading the mail: {} ({:.2f}%)' | |
if succeeded > 0: | |
percent = succeeded/len(leads)*100 | |
else: | |
percent = 0 | |
print(msg.format(succeeded, percent)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment