From 5302e1f645e451c2297be313002fa6ccd9b83b53 Mon Sep 17 00:00:00 2001 From: Keyur Date: Mon, 10 Feb 2020 16:13:42 -0800 Subject: [PATCH] Add: Functions to update User and Company profiles Add: Functions to update User and Company profiles Refactor: Update README.md Bump version to 1.0.5 --- README.md | 184 ++++++++++++++++++++++++++ moesif_aws_lambda/middleware.py | 23 +++- moesif_aws_lambda/update_companies.py | 117 ++++++++++++++++ moesif_aws_lambda/update_users.py | 117 ++++++++++++++++ setup.py | 2 +- 5 files changed, 441 insertions(+), 2 deletions(-) create mode 100644 moesif_aws_lambda/update_companies.py create mode 100644 moesif_aws_lambda/update_users.py diff --git a/README.md b/README.md index 0d37b30..cafed76 100644 --- a/README.md +++ b/README.md @@ -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). diff --git a/moesif_aws_lambda/middleware.py b/moesif_aws_lambda/middleware.py index 1104558..3d31e28 100644 --- a/moesif_aws_lambda/middleware.py +++ b/moesif_aws_lambda/middleware.py @@ -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 @@ -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): @@ -267,7 +288,7 @@ def after(self, retval): # Send event to Moesif if self.DEBUG: print('Moesif Event Model:') - pprint(self.event) + print(json.dumps(self.event)) event_send = self.api_client.create_event(event_model) if self.DEBUG: diff --git a/moesif_aws_lambda/update_companies.py b/moesif_aws_lambda/update_companies.py new file mode 100644 index 0000000..873978b --- /dev/null +++ b/moesif_aws_lambda/update_companies.py @@ -0,0 +1,117 @@ +from moesifapi.moesif_api_client import * +from moesifapi.api_helper import * +from moesifapi.exceptions.api_exception import * +from moesifapi.models import * + + +class Company: + + + def update_company(self, company_profile, api_client, moesif_options): + DEBUG = moesif_options.get('DEBUG', False) + if not company_profile: + print('Expecting the input to be either of the type - CompanyModel, dict or json while updating company') + else: + if isinstance(company_profile, dict): + if 'company_id' in company_profile: + try: + api_client.update_company(CompanyModel.from_dictionary(company_profile)) + if DEBUG: + print('Company Profile updated successfully') + except APIException as inst: + if 401 <= inst.response_code <= 403: + print("Unauthorized access sending event to Moesif. Please check your Appplication Id.") + if DEBUG: + print("Error while updating company, with status code:") + print(inst.response_code) + else: + print('To update an company, an company_id field is required') + + elif isinstance(company_profile, CompanyModel): + if company_profile.company_id is not None: + try: + api_client.update_company(company_profile) + if DEBUG: + print('Company Profile updated successfully') + except APIException as inst: + if 401 <= inst.response_code <= 403: + print("Unauthorized access sending event to Moesif. Please check your Appplication Id.") + if DEBUG: + print("Error while updating company, with status code:") + print(inst.response_code) + else: + print('To update a company, a company_id field is required') + else: + try: + company_profile_json = APIHelper.json_deserialize(company_profile) + if 'company_id' in company_profile_json: + try: + api_client.update_company(CompanyModel.from_dictionary(company_profile_json)) + if DEBUG: + print('Company Profile updated successfully') + except APIException as inst: + if 401 <= inst.response_code <= 403: + print("Unauthorized access sending event to Moesif. Please check your Appplication Id.") + if DEBUG: + print("Error while updating company, with status code:") + print(inst.response_code) + else: + print('To update a company, an company_id field is required') + except: + print('Error while deserializing the json, please make sure the json is valid') + + def update_companies_batch(self, company_profiles, api_client, moesif_options): + DEBUG = moesif_options.get('DEBUG', False) + if not company_profiles: + print('Expecting the input to be either of the type - List of CompanyModel, dict or json while updating companies') + else: + if all(isinstance(company, dict) for company in company_profiles): + if all('company_id' in company for company in company_profiles): + try: + batch_profiles = [CompanyModel.from_dictionary(d) for d in company_profiles] + api_client.update_companies_batch(batch_profiles) + if DEBUG: + print('Company Profile updated successfully') + except APIException as inst: + if 401 <= inst.response_code <= 403: + print("Unauthorized access sending event to Moesif. Please check your Appplication Id.") + if DEBUG: + print("Error while updating companies, with status code:") + print(inst.response_code) + else: + print('To update companies, an company_id field is required') + + elif all(isinstance(company, CompanyModel) for company in company_profiles): + if all(company.company_id is not None for company in company_profiles): + try: + api_client.update_companies_batch(company_profiles) + if DEBUG: + print('Company Profile updated successfully') + except APIException as inst: + if 401 <= inst.response_code <= 403: + print("Unauthorized access sending event to Moesif. Please check your Appplication Id.") + if DEBUG: + print("Error while updating companies, with status code:") + print(inst.response_code) + else: + print('To update companies, an company_id field is required') + else: + try: + company_profiles_json = [APIHelper.json_deserialize(d) for d in company_profiles] + if all(isinstance(company, dict) for company in company_profiles_json) and all( + 'company_id' in user for user in company_profiles_json): + try: + batch_profiles = [CompanyModel.from_dictionary(d) for d in company_profiles_json] + api_client.update_companies_batch(batch_profiles) + if DEBUG: + print('Company Profile updated successfully') + except APIException as inst: + if 401 <= inst.response_code <= 403: + print("Unauthorized access sending event to Moesif. Please check your Appplication Id.") + if DEBUG: + print("Error while updating companies, with status code:") + print(inst.response_code) + else: + print('To update companies, an company_id field is required') + except: + print('Error while deserializing the json, please make sure the json is valid') diff --git a/moesif_aws_lambda/update_users.py b/moesif_aws_lambda/update_users.py new file mode 100644 index 0000000..8a6f803 --- /dev/null +++ b/moesif_aws_lambda/update_users.py @@ -0,0 +1,117 @@ +from moesifapi.models import * +from moesifapi.exceptions.api_exception import * +from moesifapi.api_helper import * +from moesifapi.moesif_api_client import * + + +class User: + + + def update_user(self, user_profile, api_client, moesif_options): + DEBUG = moesif_options.get('DEBUG', False) + if not user_profile: + print('Expecting the input to be either of the type - UserModel, dict or json while updating user') + else: + if isinstance(user_profile, dict): + if 'user_id' in user_profile: + try: + api_client.update_user(UserModel.from_dictionary(user_profile)) + if DEBUG: + print('User Profile updated successfully') + except APIException as inst: + if 401 <= inst.response_code <= 403: + print("Unauthorized access sending event to Moesif. Please check your Appplication Id.") + if DEBUG: + print("Error while updating user, with status code:") + print(inst.response_code) + else: + print('To update an user, an user_id field is required') + + elif isinstance(user_profile, UserModel): + if user_profile.user_id is not None: + try: + api_client.update_user(user_profile) + if DEBUG: + print('User Profile updated successfully') + except APIException as inst: + if 401 <= inst.response_code <= 403: + print("Unauthorized access sending event to Moesif. Please check your Appplication Id.") + if DEBUG: + print("Error while updating user, with status code:") + print(inst.response_code) + else: + print('To update an user, an user_id field is required') + else: + try: + user_profile_json = APIHelper.json_deserialize(user_profile) + if 'user_id' in user_profile_json: + try: + api_client.update_user(UserModel.from_dictionary(user_profile_json)) + if DEBUG: + print('User Profile updated successfully') + except APIException as inst: + if 401 <= inst.response_code <= 403: + print("Unauthorized access sending event to Moesif. Please check your Appplication Id.") + if DEBUG: + print("Error while updating user, with status code:") + print(inst.response_code) + else: + print('To update an user, an user_id field is required') + except: + print('Error while deserializing the json, please make sure the json is valid') + + def update_users_batch(self, user_profiles, api_client, moesif_options): + DEBUG = moesif_options.get('DEBUG', False) + if not user_profiles: + print('Expecting the input to be either of the type - List of UserModel, dict or json while updating users') + else: + if all(isinstance(user, dict) for user in user_profiles): + if all('user_id' in user for user in user_profiles): + try: + batch_profiles = [UserModel.from_dictionary(d) for d in user_profiles] + api_client.update_users_batch(batch_profiles) + if DEBUG: + print('User Profile updated successfully') + except APIException as inst: + if 401 <= inst.response_code <= 403: + print("Unauthorized access sending event to Moesif. Please check your Appplication Id.") + if DEBUG: + print("Error while updating users, with status code:") + print(inst.response_code) + else: + print('To update users, an user_id field is required') + + elif all(isinstance(user, UserModel) for user in user_profiles): + if all(user.user_id is not None for user in user_profiles): + try: + api_client.update_users_batch(user_profiles) + if DEBUG: + print('User Profile updated successfully') + except APIException as inst: + if 401 <= inst.response_code <= 403: + print("Unauthorized access sending event to Moesif. Please check your Appplication Id.") + if DEBUG: + print("Error while updating users, with status code:") + print(inst.response_code) + else: + print('To update users, an user_id field is required') + else: + try: + user_profiles_json = [APIHelper.json_deserialize(d) for d in user_profiles] + if all(isinstance(user, dict) for user in user_profiles_json) and all( + 'user_id' in user for user in user_profiles_json): + try: + batch_profiles = [UserModel.from_dictionary(d) for d in user_profiles_json] + api_client.update_users_batch(batch_profiles) + if DEBUG: + print('User Profile updated successfully') + except APIException as inst: + if 401 <= inst.response_code <= 403: + print("Unauthorized access sending event to Moesif. Please check your Appplication Id.") + if DEBUG: + print("Error while updating users, with status code:") + print(inst.response_code) + else: + print('To update users, an user_id field is required') + except: + print('Error while deserializing the json, please make sure the json is valid') diff --git a/setup.py b/setup.py index 5e001a4..b4f061f 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ # Versions should comply with PEP440. For a discussion on single-sourcing # the version across setup.py and the project code, see # https://packaging.python.org/en/latest/single_source_version.html - version='1.0.4', + version='1.0.5', description='Moesif Middleware to automatically log API calls from AWS Lambda functions', long_description=long_description,