Report the user's name and company to Marketo

Also fixes the API to report the other changes (username and email) as well
This commit is contained in:
Joseph Schorr 2016-11-09 15:29:53 -05:00
parent 860942ece1
commit 1a61ef4e04
8 changed files with 78 additions and 24 deletions

View file

@ -337,7 +337,8 @@ class User(BaseModel):
enabled = BooleanField(default=True) enabled = BooleanField(default=True)
invoice_email_address = CharField(null=True, index=True) invoice_email_address = CharField(null=True, index=True)
name = CharField(null=True) given_name = CharField(null=True)
family_name = CharField(null=True)
company = CharField(null=True) company = CharField(null=True)
def delete_instance(self, recursive=False, delete_nullable=False): def delete_instance(self, recursive=False, delete_nullable=False):

View file

@ -1,23 +1,25 @@
"""Add user metadata fields """Add user metadata fields
Revision ID: 491a530df230 Revision ID: faf752bd2e0a
Revises: 6c7014e84a5e Revises: 6c7014e84a5e
Create Date: 2016-11-04 18:03:05.237408 Create Date: 2016-11-14 17:29:03.984665
""" """
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '491a530df230' revision = 'faf752bd2e0a'
down_revision = '6c7014e84a5e' down_revision = '6c7014e84a5e'
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from util.migrate import UTF8CharField from util.migrate import UTF8CharField
def upgrade(tables): def upgrade(tables):
### commands auto generated by Alembic - please adjust! ### ### commands auto generated by Alembic - please adjust! ###
op.add_column('user', sa.Column('company', UTF8CharField(length=255), nullable=True)) op.add_column('user', sa.Column('company', UTF8CharField(length=255), nullable=True))
op.add_column('user', sa.Column('name', UTF8CharField(length=255), nullable=True)) op.add_column('user', sa.Column('family_name', UTF8CharField(length=255), nullable=True))
op.add_column('user', sa.Column('given_name', UTF8CharField(length=255), nullable=True))
### end Alembic commands ### ### end Alembic commands ###
op.bulk_insert(tables.userpromptkind, op.bulk_insert(tables.userpromptkind,
@ -29,7 +31,8 @@ def upgrade(tables):
def downgrade(tables): def downgrade(tables):
### commands auto generated by Alembic - please adjust! ### ### commands auto generated by Alembic - please adjust! ###
op.drop_column('user', 'name') op.drop_column('user', 'given_name')
op.drop_column('user', 'family_name')
op.drop_column('user', 'company') op.drop_column('user', 'company')
### end Alembic commands ### ### end Alembic commands ###

View file

@ -355,10 +355,11 @@ def list_entity_robot_permission_teams(entity_name, include_permissions=False):
return TupleSelector(query, fields) return TupleSelector(query, fields)
def update_user_metadata(user, name=None, company=None): def update_user_metadata(user, given_name=None, family_name=None, company=None):
""" Updates the metadata associated with the user, including his/her name and company. """ """ Updates the metadata associated with the user, including his/her name and company. """
with db_transaction(): with db_transaction():
user.name = name or user.name user.given_name = given_name or user.given_name
user.family_name = family_name or user.family_name
user.company = company or user.company user.company = company or user.company
user.save() user.save()

View file

@ -213,9 +213,13 @@ class User(ApiResource):
'type': ['string', 'null'], 'type': ['string', 'null'],
'description': 'Custom email address for receiving invoices', 'description': 'Custom email address for receiving invoices',
}, },
'name': { 'given_name': {
'type': 'string', 'type': 'string',
'description': 'The optional entered name for the user', 'description': 'The optional entered given name for the user',
},
'family_name': {
'type': 'string',
'description': 'The optional entered family name for the user',
}, },
'company': { 'company': {
'type': 'string', 'type': 'string',
@ -332,10 +336,14 @@ class User(ApiResource):
code = model.user.create_confirm_email_code(user, new_email=new_email) code = model.user.create_confirm_email_code(user, new_email=new_email)
send_change_email(user.username, user_data['email'], code.code) send_change_email(user.username, user_data['email'], code.code)
else: else:
user_analytics.change_email(user.email, new_email)
model.user.update_email(user, new_email, auto_verify=not features.MAILING) model.user.update_email(user, new_email, auto_verify=not features.MAILING)
if 'name' in user_data or 'company' in user_data: if 'given_name' in user_data or 'family_name' in user_data or 'company' in user_data:
model.user.update_user_metadata(user, user_data.get('name'), user_data.get('company')) model.user.update_user_metadata(user, user_data.get('given_name'),
user_data.get('family_name'), user_data.get('company'))
user_analytics.change_metadata(user.email, user_data.get('given_name'),
user_data.get('family_name'), user_data.get('company'))
# Check for username rename. A username can be renamed if the feature is enabled OR the user # Check for username rename. A username can be renamed if the feature is enabled OR the user
# currently has a confirm_username prompt. # currently has a confirm_username prompt.
@ -353,6 +361,7 @@ class User(ApiResource):
raise request_error(message='Username is already in use') raise request_error(message='Username is already in use')
user = model.user.change_username(user.id, new_username) user = model.user.change_username(user.id, new_username)
user_analytics.change_username(user.email, new_username)
elif confirm_username: elif confirm_username:
model.user.remove_user_prompt(user, 'confirm_username') model.user.remove_user_prompt(user, 'confirm_username')

View file

@ -122,7 +122,8 @@ def common_login(db_user, permanent_session=True):
session.permanent_session_lifetime = convert_to_timedelta(session_timeout_str) session.permanent_session_lifetime = convert_to_timedelta(session_timeout_str)
# Inform our user analytics that we have a new "lead" # Inform our user analytics that we have a new "lead"
user_analytics.create_lead(db_user.email, db_user.username) user_analytics.create_lead(db_user.email, db_user.username, db_user.given_name,
db_user.family_name, db_user.company)
return True return True
else: else:
logger.debug('User could not be logged in, inactive?.') logger.debug('User could not be logged in, inactive?.')

View file

@ -42,19 +42,28 @@
<form name="metadataForm" ng-submit="updateUser(metadata)" style="margin-top: 20px;"> <form name="metadataForm" ng-submit="updateUser(metadata)" style="margin-top: 20px;">
<div class="form-group nested"> <div class="form-group nested">
<label for="name">Name</label> <label for="givenName">Given Name</label>
<div class="field-row"> <div class="field-row">
<span class="field-container"> <span class="field-container">
<input type="text" class="form-control" placeholder="Name" ng-model="metadata.name"></span> <input type="text" class="form-control" placeholder="Given Name" ng-model="metadata.given_name" name="givenName">
</span> </span>
</div> </div>
</div> </div>
<div class="form-group nested"> <div class="form-group nested">
<label for="firstName">Company</label> <label for="familyName">Family Name</label>
<div class="field-row"> <div class="field-row">
<span class="field-container"> <span class="field-container">
<input type="text" class="form-control" placeholder="Company name" ng-model="metadata.company"></span> <input type="text" class="form-control" placeholder="Family Name" ng-model="metadata.family_name" name="familyName">
</span>
</div>
</div>
<div class="form-group nested">
<label for="company">Company</label>
<div class="field-row">
<span class="field-container">
<input type="text" class="form-control" placeholder="Company name" ng-model="metadata.company" name="company"></span>
</span> </span>
</div> </div>
</div> </div>

Binary file not shown.

View file

@ -27,13 +27,29 @@ class _MarketoAnalyticsClient(object):
self._munchkin_private_key = munchkin_private_key self._munchkin_private_key = munchkin_private_key
self._lead_source = lead_source self._lead_source = lead_source
def create_lead(self, email, username): def _get_lead_metadata(self, given_name, family_name, company):
metadata = {}
if given_name:
metadata['firstName'] = given_name
if family_name:
metadata['lastName'] = family_name
if company:
metadata['company'] = company
return metadata
def create_lead(self, email, username, given_name, family_name, company):
lead_data = dict( lead_data = dict(
email=email, email=email,
Quay_Username__c=username, Quay_Username__c=username,
leadSource='Web - Product Trial', leadSource='Web - Product Trial',
Lead_Source_Detail__c=self._lead_source, Lead_Source_Detail__c=self._lead_source,
) )
lead_data.update(self._get_lead_metadata(given_name, family_name, company))
self._marketo.create_update_leads( self._marketo.create_update_leads(
action='createOrUpdate', action='createOrUpdate',
leads=[lead_data], leads=[lead_data],
@ -65,16 +81,30 @@ class _MarketoAnalyticsClient(object):
lookupField='id', lookupField='id',
) )
def change_username(self, email, new_username): def change_metadata(self, email, given_name, family_name, company):
found = self._find_leads_by_email(email) lead_data = self._get_lead_metadata(given_name, family_name, company)
if not lead_data:
return
# Update using their user id. # Update using their email address.
updated = [dict(id=lead['id'], Quay_Username__c=new_username) for lead in found] lead_data['email'] = email
self._marketo.create_update_leads( self._marketo.create_update_leads(
action='updateOnly', action='updateOnly',
leads=updated, leads=[lead_data],
asyncProcessing=True, asyncProcessing=True,
lookupField='id', 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 @AsyncExecutorWrapper.sync