mirror of
https://github.com/quay/quay.git
synced 2026-01-27 18:42:52 +03:00
179 lines
5.8 KiB
Python
179 lines
5.8 KiB
Python
import logging
|
|
|
|
from hashlib import sha1
|
|
|
|
from concurrent.futures import ThreadPoolExecutor
|
|
from marketorestpython.client import MarketoClient
|
|
|
|
from util.asyncwrapper import AsyncExecutorWrapper, NullExecutor, NullExecutorCancelled
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class LeadNotFoundException(Exception):
|
|
pass
|
|
|
|
|
|
def build_error_callback(message_when_exception):
|
|
def maybe_log_error(response_future):
|
|
try:
|
|
response_future.result()
|
|
except NullExecutorCancelled:
|
|
pass
|
|
except Exception:
|
|
logger.exception("User analytics: %s", message_when_exception)
|
|
|
|
return maybe_log_error
|
|
|
|
|
|
class _MarketoAnalyticsClient(object):
|
|
"""
|
|
User analytics implementation which will report user changes to the Marketo API.
|
|
"""
|
|
|
|
def __init__(self, marketo_client, munchkin_private_key, lead_source):
|
|
"""
|
|
Instantiate with the given marketorestpython.client, the Marketo Munchkin Private Key, and
|
|
the Lead Source that we want to set when we create new lead records in Marketo.
|
|
"""
|
|
self._marketo = marketo_client
|
|
self._munchkin_private_key = munchkin_private_key
|
|
self._lead_source = lead_source
|
|
|
|
def _get_lead_metadata(self, given_name, family_name, company, location):
|
|
metadata = {}
|
|
if given_name:
|
|
metadata["firstName"] = given_name
|
|
|
|
if family_name:
|
|
metadata["lastName"] = family_name
|
|
|
|
if company:
|
|
metadata["company"] = company
|
|
|
|
if location:
|
|
metadata["location"] = location
|
|
|
|
return metadata
|
|
|
|
def create_lead(self, email, username, given_name, family_name, company, location):
|
|
lead_data = dict(
|
|
email=email,
|
|
Quay_Username__c=username,
|
|
leadSource="Web - Product Trial",
|
|
Lead_Source_Detail__c=self._lead_source,
|
|
)
|
|
|
|
lead_data.update(self._get_lead_metadata(given_name, family_name, company, location))
|
|
|
|
self._marketo.create_update_leads(
|
|
action="createOrUpdate", leads=[lead_data], asyncProcessing=True, lookupField="email",
|
|
)
|
|
|
|
def _find_leads_by_email(self, email):
|
|
# Fetch the existing user from the database by email
|
|
found = self._marketo.get_multiple_leads_by_filter_type(
|
|
filterType="email", filterValues=[email],
|
|
)
|
|
|
|
if not found:
|
|
raise LeadNotFoundException("No lead found with email: {}".format(email))
|
|
|
|
return found
|
|
|
|
def change_email(self, old_email, new_email):
|
|
found = self._find_leads_by_email(old_email)
|
|
|
|
# Update using their user id.
|
|
updated = [dict(id=lead["id"], email=new_email) for lead in found]
|
|
self._marketo.create_update_leads(
|
|
action="updateOnly", leads=updated, asyncProcessing=True, lookupField="id",
|
|
)
|
|
|
|
def change_metadata(
|
|
self, email, given_name=None, family_name=None, company=None, location=None
|
|
):
|
|
lead_data = self._get_lead_metadata(given_name, family_name, company, location)
|
|
if not lead_data:
|
|
return
|
|
|
|
# Update using their email address.
|
|
lead_data["email"] = email
|
|
self._marketo.create_update_leads(
|
|
action="updateOnly", leads=[lead_data], asyncProcessing=True, lookupField="email",
|
|
)
|
|
|
|
def change_username(self, email, new_username):
|
|
# Update using their email.
|
|
self._marketo.create_update_leads(
|
|
action="updateOnly",
|
|
leads=[{"email": email, "Quay_Username__c": new_username,}],
|
|
asyncProcessing=True,
|
|
lookupField="email",
|
|
)
|
|
|
|
@AsyncExecutorWrapper.sync
|
|
def get_user_analytics_metadata(self, user_obj):
|
|
"""
|
|
Return a list of properties that should be added to the user object to allow analytics
|
|
associations.
|
|
"""
|
|
if not self._munchkin_private_key:
|
|
return dict()
|
|
|
|
marketo_user_hash = sha1(self._munchkin_private_key)
|
|
marketo_user_hash.update(user_obj.email)
|
|
|
|
return dict(marketo_user_hash=marketo_user_hash.hexdigest(),)
|
|
|
|
|
|
class UserAnalytics(object):
|
|
def __init__(self, app=None):
|
|
self.app = app
|
|
if app is not None:
|
|
self.state = self.init_app(app)
|
|
else:
|
|
self.state = None
|
|
|
|
def init_app(self, app):
|
|
analytics_type = app.config.get("USER_ANALYTICS_TYPE", "FakeAnalytics")
|
|
|
|
marketo_munchkin_id = ""
|
|
marketo_munchkin_private_key = ""
|
|
marketo_client_id = ""
|
|
marketo_client_secret = ""
|
|
marketo_lead_source = ""
|
|
executor = NullExecutor()
|
|
|
|
if analytics_type == "Marketo":
|
|
marketo_munchkin_id = app.config["MARKETO_MUNCHKIN_ID"]
|
|
marketo_munchkin_private_key = app.config["MARKETO_MUNCHKIN_PRIVATE_KEY"]
|
|
marketo_client_id = app.config["MARKETO_CLIENT_ID"]
|
|
marketo_client_secret = app.config["MARKETO_CLIENT_SECRET"]
|
|
marketo_lead_source = app.config["MARKETO_LEAD_SOURCE"]
|
|
|
|
logger.debug(
|
|
"Initializing marketo with keys: %s %s %s",
|
|
marketo_munchkin_id,
|
|
marketo_client_id,
|
|
marketo_client_secret,
|
|
)
|
|
|
|
executor = ThreadPoolExecutor(max_workers=1)
|
|
|
|
marketo_client = MarketoClient(
|
|
marketo_munchkin_id, marketo_client_id, marketo_client_secret
|
|
)
|
|
client_wrapper = _MarketoAnalyticsClient(
|
|
marketo_client, marketo_munchkin_private_key, marketo_lead_source
|
|
)
|
|
user_analytics = AsyncExecutorWrapper(client_wrapper, executor)
|
|
|
|
# register extension with app
|
|
app.extensions = getattr(app, "extensions", {})
|
|
app.extensions["user_analytics"] = user_analytics
|
|
return user_analytics
|
|
|
|
def __getattr__(self, name):
|
|
return getattr(self.state, name, None)
|