Skip to content

Commit

Permalink
Merge pull request #6 from Moesif/add-user-company-functions
Browse files Browse the repository at this point in the history
Add: Functions to update User and Company profiles
  • Loading branch information
dkm199 authored Feb 14, 2020
2 parents 284875c + 6d382bd commit 323765c
Show file tree
Hide file tree
Showing 5 changed files with 509 additions and 54 deletions.
184 changes: 184 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,190 @@ Type: `Boolean`

`LOG_BODY` is default to true, set to false to remove logging request and response body to Moesif.

## Update User

### Update A Single User
Create or update a user profile in Moesif.
The metadata field can be any customer demographic or other info you want to store.
Only the `user_id` field is required.
For details, visit the [Python API Reference](https://www.moesif.com/docs/api?python#update-a-user).

```python
from moesif_aws_lambda.middleware import *

moesif_options = {
'LOG_BODY': True,
'DEBUG': True,
}

# Only user_id is required.
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
# See https://www.moesif.com/docs/api#users for campaign schema
# metadata can be any custom object
user = {
'user_id': '12345',
'company_id': '67890', # If set, associate user with a company object
'campaign': {
'utm_source': 'google',
'utm_medium': 'cpc',
'utm_campaign': 'adwords',
'utm_term': 'api+tooling',
'utm_content': 'landing'
},
'metadata': {
'email': 'john@acmeinc.com',
'first_name': 'John',
'last_name': 'Doe',
'title': 'Software Engineer',
'sales_info': {
'stage': 'Customer',
'lifetime_value': 24000,
'account_owner': 'mary@contoso.com'
},
}
}

update_user(user, moesif_options)
```

### Update Users in Batch
Similar to update_user, but used to update a list of users in one batch.
Only the `user_id` field is required.
For details, visit the [Python API Reference](https://www.moesif.com/docs/api?python#update-users-in-batch).

```python
from moesif_aws_lambda.middleware import *

moesif_options = {
'LOG_BODY': True,
'DEBUG': True,
}

userA = {
'user_id': '12345',
'company_id': '67890', # If set, associate user with a company object
'metadata': {
'email': 'john@acmeinc.com',
'first_name': 'John',
'last_name': 'Doe',
'title': 'Software Engineer',
'sales_info': {
'stage': 'Customer',
'lifetime_value': 24000,
'account_owner': 'mary@contoso.com'
},
}
}

userB = {
'user_id': '54321',
'company_id': '67890', # If set, associate user with a company object
'metadata': {
'email': 'mary@acmeinc.com',
'first_name': 'Mary',
'last_name': 'Jane',
'title': 'Software Engineer',
'sales_info': {
'stage': 'Customer',
'lifetime_value': 48000,
'account_owner': 'mary@contoso.com'
},
}
}
update_users_batch([userA, userB], moesif_options)
```

## Update Company

### Update A Single Company
Create or update a company profile in Moesif.
The metadata field can be any company demographic or other info you want to store.
Only the `company_id` field is required.
For details, visit the [Python API Reference](https://www.moesif.com/docs/api?python#update-a-company).

```python
from moesif_aws_lambda.middleware import *

moesif_options = {
'LOG_BODY': True,
'DEBUG': True,
}

# Only company_id is required.
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
# See https://www.moesif.com/docs/api#update-a-company for campaign schema
# metadata can be any custom object
company = {
'company_id': '67890',
'company_domain': 'acmeinc.com', # If domain is set, Moesif will enrich your profiles with publicly available info
'campaign': {
'utm_source': 'google',
'utm_medium': 'cpc',
'utm_campaign': 'adwords',
'utm_term': 'api+tooling',
'utm_content': 'landing'
},
'metadata': {
'org_name': 'Acme, Inc',
'plan_name': 'Free',
'deal_stage': 'Lead',
'mrr': 24000,
'demographics': {
'alexa_ranking': 500000,
'employee_count': 47
},
}
}

update_company(company, moesif_options)
```

### Update Companies in Batch
Similar to update_company, but used to update a list of companies in one batch.
Only the `company_id` field is required.
For details, visit the [Python API Reference](https://www.moesif.com/docs/api?python#update-companies-in-batch).

```python
from moesif_aws_lambda.middleware import *

moesif_options = {
'LOG_BODY': True,
'DEBUG': True,
}

companyA = {
'company_id': '67890',
'company_domain': 'acmeinc.com', # If domain is set, Moesif will enrich your profiles with publicly available info
'metadata': {
'org_name': 'Acme, Inc',
'plan_name': 'Free',
'deal_stage': 'Lead',
'mrr': 24000,
'demographics': {
'alexa_ranking': 500000,
'employee_count': 47
},
}
}

companyB = {
'company_id': '09876',
'company_domain': 'contoso.com', # If domain is set, Moesif will enrich your profiles with publicly available info
'metadata': {
'org_name': 'Contoso, Inc',
'plan_name': 'Free',
'deal_stage': 'Lead',
'mrr': 48000,
'demographics': {
'alexa_ranking': 500000,
'employee_count': 53
},
}
}

update_companies_batch([companyA, companyB], moesif_options)
```

## Examples

- [A complete example is available on GitHub](https://github.com/Moesif/moesif-aws-lambda-python-example).
Expand Down
143 changes: 90 additions & 53 deletions moesif_aws_lambda/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from moesifapi.exceptions.api_exception import *
from moesifapi.models import *
from .client_ip import ClientIp
from .update_companies import Company
from .update_users import User
from datetime import *
import base64
import json
Expand All @@ -16,6 +18,25 @@
except ImportError:
from urllib.parse import urlencode

# Initialized the client
if os.environ["MOESIF_APPLICATION_ID"]:
api_client = MoesifAPIClient(os.environ["MOESIF_APPLICATION_ID"]).api
else:
raise Exception('Moesif Application ID is required in settings')

def update_user(user_profile, moesif_options):
User().update_user(user_profile, api_client, moesif_options)

def update_users_batch(user_profiles, moesif_options):
User().update_users_batch(user_profiles, api_client, moesif_options)

def update_company(company_profile, moesif_options):
Company().update_company(company_profile, api_client, moesif_options)

def update_companies_batch(companies_profiles, moesif_options):
Company().update_companies_batch(companies_profiles, api_client, moesif_options)


def MoesifLogger(moesif_options):
class log_data(LambdaDecorator):
def __init__(self, handler):
Expand All @@ -31,14 +52,23 @@ def __init__(self, handler):
self.DEBUG = self.moesif_options.get('DEBUG', False)
self.event = None
self.context = None
self.start_time = datetime.utcnow()

# Intialized the client
if os.environ.get("MOESIF_APPLICATION_ID"):
self.api_client = MoesifAPIClient(os.environ["MOESIF_APPLICATION_ID"]).api
else:
raise Exception('Moesif Application ID is required in settings')

def clear_state(self):
"""Function to clear state of local variable"""
self.event = None
self.context = None
self.event_req = None
self.metadata = None
self.session_token = None
self.user_id = None
self.company_id = None

def get_user_id(self, event, context):
"""Function to fetch UserId"""
username = None
Expand Down Expand Up @@ -109,10 +139,19 @@ def process_body(self, body_wrapper):
def before(self, event, context):
"""This function runs before the handler is invoked, is passed the event & context and must return an event & context too."""

# Clear the state of the local variables
self.clear_state()

# Set/Save event and context for use Skip Event function
self.event = event
self.context = context

# Request Method
request_verb = event.get('httpMethod')
if request_verb is None:
print('MOESIF: [before] AWS Lambda trigger must be a Load Balancer or API Gateway See https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html or https://docs.aws.amazon.com/lambda/latest/dg/with-on-demand-https.html.')
self.event = None
self.context = None
return event, context

# Request headers
Expand All @@ -128,9 +167,9 @@ def before(self, event, context):
# Request Time
epoch = event and event.get('request_context', {}).get('requestTimeEpoch')
if epoch is not None:
request_time =datetime.utcfromtimestamp(epoch)
request_time = datetime.utcfromtimestamp(epoch)
else:
request_time = self.start_time
request_time = datetime.utcnow()

# Request Body
req_body, req_transfer_encoding = self.process_body(event)
Expand Down Expand Up @@ -213,66 +252,64 @@ def before(self, event, context):
body = req_body,
transfer_encoding = req_transfer_encoding)

# Set/Save event and context for use Skip Event function
self.event = event
self.context = context

# Return event, context
return event, context

def after(self, retval):
"""This function runs after the handler is invoked, is passed the response and must return an response too."""
# Response body
resp_body, resp_transfer_encoding = self.process_body(retval)

if self.event is not None:
# Response body
resp_body, resp_transfer_encoding = self.process_body(retval)

# Event Response object
event_rsp = EventResponseModel(time = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3],
status = retval.get('statusCode', 599),
headers = retval.get('headers', {}),
body = resp_body,
transfer_encoding = resp_transfer_encoding)
# Event Response object
event_rsp = EventResponseModel(time = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3],
status = retval.get('statusCode', 599),
headers = retval.get('headers', {}),
body = resp_body,
transfer_encoding = resp_transfer_encoding)

# Event object
event_model = EventModel(request = self.event_req,
response = event_rsp,
user_id = self.user_id,
company_id = self.company_id,
session_token = self.session_token,
metadata = self.metadata)

# Mask Event Model
try:
mask_event_model = self.moesif_options.get('MASK_EVENT_MODEL', None)
if mask_event_model is not None:
event_model = mask_event_model(event_model)
except:
if self.DEBUG:
print("MOESIF Can not execute MASK_EVENT_MODEL function. Please check moesif settings.")
# Event object
event_model = EventModel(request = self.event_req,
response = event_rsp,
user_id = self.user_id,
company_id = self.company_id,
session_token = self.session_token,
metadata = self.metadata)
# Mask Event Model
try:
mask_event_model = self.moesif_options.get('MASK_EVENT_MODEL', None)
if mask_event_model is not None:
event_model = mask_event_model(event_model)
except:
if self.DEBUG:
print("MOESIF Can not execute MASK_EVENT_MODEL function. Please check moesif settings.")

# Skip Event
try:
skip_event = self.moesif_options.get('SKIP', None)
if skip_event is not None:
if skip_event(self.event, self.context):
if self.DEBUG:
print('MOESIF Skip sending event to Moesif')
return retval
except:
if self.DEBUG:
print("MOESIF Having difficulty executing skip_event function. Please check moesif settings.")
# Skip Event
try:
skip_event = self.moesif_options.get('SKIP', None)
if skip_event is not None:
if skip_event(self.event, self.context):
if self.DEBUG:
print('MOESIF Skip sending event to Moesif')
return retval
except:
if self.DEBUG:
print("MOESIF Having difficulty executing skip_event function. Please check moesif settings.")

# Add direction field
event_model.direction = "Incoming"
# Add direction field
event_model.direction = "Incoming"

# Send event to Moesif
if self.DEBUG:
print('Moesif Event Model:')
print(json.dumps(self.event))

event_send = self.api_client.create_event(event_model)
if self.DEBUG:
print('MOESIF ' + str(event_send))

# Send event to Moesif
if self.DEBUG:
print('Moesif Event Model:')
pprint(self.event)

event_send = self.api_client.create_event(event_model)
if self.DEBUG:
print('MOESIF ' + str(event_send))

# Send response
return retval

Expand Down
Loading

0 comments on commit 323765c

Please sign in to comment.