Files
OSIT-AE-API-FastAPI/app/methods/e_cvent_methods.py
2023-01-30 16:28:15 -05:00

799 lines
35 KiB
Python

import datetime, json, pprint, pytz, random, requests, secrets, string, time
from requests.auth import HTTPBasicAuth
from typing import Dict, List, Optional, Set, Union
from pydantic import BaseModel, EmailStr, Field, PrivateAttr, ValidationError, validator
from app.db_sql import redis_lookup_id_random, sql_insert, sql_select, sql_update
from app.lib_general import log, logging, logger_reset, secure_hash_string, verify_secure_hash_string
from app.methods.c_idaa_methods import refresh_person_group
from app.methods.person_methods import create_person_kiss, get_person_rec_list, get_person_rec_w_external_id, load_person_obj, update_person_kiss
from app.methods.membership_person_methods import create_membership_person_obj, update_membership_person_obj
app = {}
app['client_id'] = '0oalt6dz82oSbN9ok1t7' # From Cvent Developer Portal
app['secret'] = 'gQY96qffZAuB_44k73C_hn_MHeByBS8LXHj1vPRm' # From Cvent Developer Portal
api = {}
api['base_url'] = 'https://api-platform.cvent.com/ea' # Including /ea as the Cvent version. EA = Early Access
api['headers'] = {} # { 'Content-Type': content_type, 'Authorization': 'Basic '+str(cvent_authorization_base64) }
# ### BEGIN ### API External Cvent Methods ### get_access_token() ###
# Updated 2022-02-01
@logger_reset
def get_access_token():
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
log.debug(f'API data:\n{api}')
# api['access_token'] = ''
if 'access_token' in api:
access_token = api.get('access_token')
log.debug(f'Cvent Access Token found: {access_token}')
else:
log.info(f'Cvent Access Token was not found. Will request one.')
if 'expire_on' in api and datetime.datetime.now() < api['expire_on']:
expire_on = api.get('expire_on')
log.debug(f'Cvent Access Token is current: {expire_on}')
return api
else:
expire_on = api.get('expire_on')
log.info(f'Cvent Access Token is not current. Requesting a new one. Expired On: {expire_on}')
endpoint = '/oauth2/token'
uri = api['base_url']+endpoint
data = { 'grant_type': 'client_credentials', 'client_id': app['client_id'] }
log.debug(f'Oauth Token Request Data:\n{api}')
try_request = True
limit = 0
while try_request and limit < 3:
limit = limit + 1
resp = requests.post(url=uri, data=data, auth=HTTPBasicAuth(app['client_id'], app['secret'])) # Sending as HTML form data
log.debug(f'Status Code: {resp.status_code}')
log.debug(f'Headers: {resp.headers}')
# log.debug(f'Encoding: {resp.encoding}')
log.debug(f'JSON: {resp.json()}')
# log.debug('Text:', resp.text)
response_data = resp.json()
log.debug(json.dumps(response_data, indent=2, default=str))
if 'message' in response_data and response_data['message'] == 'Too Many Requests':
log.warning('Hit Cvent rate limit. Sleeping for .5 seconds...')
time.sleep(.5)
elif 'access_token' in response_data:
access_token = response_data.get('access_token')
log.info(f'Got a new Access Token {access_token} from Cvent')
try_request = False
api['access_token'] = response_data['access_token']
api['expires_in'] = response_data['expires_in']
api['token_type'] = response_data['token_type']
api['expire_on'] = datetime.datetime.now() + datetime.timedelta(seconds=response_data['expires_in'])
api['headers']['Accept'] = 'application/json'
api['headers']['x-api-key'] = app['client_id']
api['headers']['Authorization'] = 'Bearer '+api['access_token']
log.debug(api)
log.warning('Sleeping for .5 seconds to avoid Cvent rate limit...')
time.sleep(.5)
return api
# ### END ### API External Cvent Methods ### get_access_token() ###
# ### BEGIN ### API External Cvent Methods ### get_group_contact_list() ###
# Updated 2022-02-09
@logger_reset
def get_group_contact_list(contact_group_id: str=None):
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
get_access_token()
# Contact Group ID for IDAA Full Mailing List: UUID = '60ef4838-5340-4e2a-9d0a-b4ef310eaa69'
endpoint = f'/contact-groups/{contact_group_id}/contacts'
uri = api['base_url']+endpoint
params = {}
try_request = True
limit = 0
next_token = None
cvent_contact_list = []
while try_request and limit < 100:
limit = limit + 1
if next_token: params['token'] = next_token
resp = requests.get(url=uri, headers=api['headers'], params=params)
response_data = resp.json()
log.debug(json.dumps(response_data, indent=2, default=str))
if 'message' in response_data and response_data['message'] == 'Too Many Requests':
log.warning('Hit Cvent rate limit. Sleeping for .5 seconds...')
time.sleep(.5)
elif 'paging' in response_data:
log.debug(json.dumps(response_data.get('paging'), indent=2, default=str))
if total_count := response_data.get('paging').get('totalCount'):
log.info(f'Found {total_count} Cvent Contact results in the Cvent Group')
cvent_contact_list = cvent_contact_list + response_data.get('data')
if next_token := response_data.get('paging').get('nextToken'):
log.warning('Sleeping for .25 seconds to avoid Cvent rate limit...')
time.sleep(.25)
else:
try_request = False
else:
log.info('No Cvent Contact results for Cvent Group')
try_request = False
next_token = None
return None
else:
log.warning('Unexpected response from Cvent API')
return False
if 'message' in response_data and response_data['message'] == 'Too Many Requests': return False
return cvent_contact_list
# ### END ### API External Cvent Methods ### get_group_contact_list() ###
# ### BEGIN ### API External Cvent Methods ### get_contact_custom_field_list() ###
# Updated 2022-01-31
@logger_reset
def get_contact_custom_field_list(api):
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
endpoint = '/custom-fields'
uri = api['base_url']+endpoint
params = { 'filter': "category eq 'Contact'" }
resp = requests.get(url=uri, headers=api['headers'], params=params)
log.debug('Status Code:', resp.status_code)
log.debug('Headers:', resp.headers)
# log.debug('Encoding:', resp.encoding)
log.debug('JSON:', resp.json())
# log.debug('Text:', resp.text)
response_data = resp.json()
# f = open('contact_custom_field_list.txt', 'w')
# f.write(pprint.pformat(response_data, indent=2, width=160))
return response_data
# ### END ### API External Cvent Methods ### get_contact_custom_field_list() ###
# ### BEGIN ### API External Cvent Methods ### get_contact_list() ###
# Updated 2022-01-31
@logger_reset
def get_contact_list(external_id: str=None, email: str=None):
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
get_access_token()
endpoint = '/contacts'
uri = api['base_url']+endpoint
# External ID for IDAA: UUID = '609ab766-7d79-4a9d-a72c-f126412659ee'
# customField.609ab766-7d79-4a9d-a72c-f126412659ee eq external_id
params = {}
if external_id:
log.info(f'Looking up Cvent Contcat with External ID: {external_id}')
params['filter'] = f"deleted eq 'False' and customField.609ab766-7d79-4a9d-a72c-f126412659ee eq '{external_id}'"
elif email:
log.info(f'Looking up Cvent Contcat with Email: {email}')
params['filter'] = f"deleted eq 'False' and email eq '{email}'"
elif external_id is None:
log.info(f'Looking up Cvent Contact(s) with empty Cvent custom field for external ID.')
params['filter'] = f"deleted eq 'False' and customField.609ab766-7d79-4a9d-a72c-f126412659ee lt '1'"
else:
log.info(f'Looking up Cvent Contact(s) that have not been marked as deleted.')
params['filter'] = f"deleted eq 'False'"
try_request = True
limit = 0
while try_request and limit < 3:
limit = limit + 1
resp = requests.get(url=uri, headers=api['headers'], params=params)
response_data = resp.json()
log.debug(json.dumps(response_data, indent=2, default=str))
if 'message' in response_data and response_data['message'] == 'Too Many Requests':
log.warning('Hit Cvent rate limit. Sleeping for .5 seconds...')
time.sleep(.5)
else:
if 'paging' in response_data:
current_token = response_data.get('paging').get('currentToken')
total_count = response_data.get('paging').get('totalCount')
log.info(f'Found {total_count} results from Cvent Contact list')
log.debug(json.dumps(response_data.get('paging'), indent=2, default=str))
try_request = False
if 'message' in response_data and response_data['message'] == 'Too Many Requests': return False
return response_data
# ### END ### API External Cvent Methods ### get_contact_list() ###
# ### BEGIN ### API External Cvent Methods ### get_recent_contact_list() ###
# Updated 2022-02-02
@logger_reset
def get_recent_contact_list(
from_created_on = None,
to_created_on = None, # datetime.datetime.utcnow(),
from_updated_on = None,
to_updated_on = None,
# get_only = 'created', # created, updated/modified
):
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
get_access_token()
endpoint = f'/contacts'
uri = api['base_url']+endpoint
params = {}
if from_created_on:
from_created_on_str = from_created_on.isoformat()
log.info(f'From Created On: {from_created_on_str}')
if to_created_on:
to_created_on_str = to_created_on.isoformat()
log.info(f'To Created On: {to_created_on_str}')
if from_updated_on:
from_updated_on_str = from_updated_on.isoformat()
log.info(f'From Updated On: {from_updated_on_str}')
if to_updated_on:
to_updated_on_str = to_updated_on.isoformat()
log.info(f'To Updated On: {to_updated_on_str}')
if from_created_on and from_updated_on and to_created_on and to_updated_on:
params['filter'] = f"deleted eq 'False' and (created gt '{from_created_on_str}Z' or lastModified gt '{from_updated_on_str}Z') and (created lt '{to_created_on_str}Z' or lastModified lt '{to_updated_on_str}Z')"
elif from_created_on and to_created_on:
params['filter'] = f"deleted eq 'False' and created gt '{from_created_on_str}Z' and created lt '{to_created_on_str}Z'"
elif from_updated_on and to_updated_on:
params['filter'] = f"deleted eq 'False' and lastModified gt '{from_updated_on_str}Z' and lastModified lt '{to_updated_on_str}Z'"
elif from_created_on:
params['filter'] = f"deleted eq 'False' and created gt '{from_created_on_str}Z'"
elif from_updated_on:
params['filter'] = f"deleted eq 'False' and lastModified gt '{from_updated_on_str}Z'"
else:
log.warning('Created On or Updated On is required. Returning False')
return False
try_request = True
limit = 0
next_token = None
cvent_contact_list = []
while try_request and limit < 100:
limit = limit + 1
if next_token: params['token'] = next_token
resp = requests.get(url=uri, headers=api['headers'], params=params)
response_data = resp.json()
log.debug(json.dumps(response_data, indent=2, default=str))
if 'message' in response_data and response_data['message'] == 'Too Many Requests':
log.warning('Hit Cvent rate limit. Sleeping for .5 seconds...')
time.sleep(.5)
elif 'paging' in response_data:
log.debug(json.dumps(response_data.get('paging'), indent=2, default=str))
if total_count := response_data.get('paging').get('totalCount'):
log.info(f'Found {total_count} Cvent Contact results')
cvent_contact_list = cvent_contact_list + response_data.get('data')
if next_token := response_data.get('paging').get('nextToken'):
log.warning('Sleeping for .25 seconds to avoid Cvent rate limit...')
time.sleep(.25)
else:
try_request = False
else:
log.info('No Cvent Contact results')
try_request = False
next_token = None
return None
else:
log.warning('Unexpected response from Cvent API')
return False
# cvent_contact_list = response_data.get('data')
# next_token = None
# if 'paging' in response_data:
# if total_count := response_data.get('paging').get('totalCount'):
# log.info(f'Found {total_count} Cvent Contact results')
# next_token = response_data.get('paging').get('nextToken')
# log.debug(json.dumps(response_data.get('paging'), indent=2, default=str))
# else:
# log.info('No Cvent Contact results')
# next_token = None
# return None
# limit = 0
# while next_token and limit < 100:
# limit = limit + 1
# params = {}
# params['token'] = next_token
# resp = requests.get(url=uri, headers=api['headers'], params=params)
# response_data = resp.json()
# # log.debug(json.dumps(response_data, indent=2, default=str))
# if 'message' in response_data and response_data['message'] == 'Too Many Requests':
# log.warning('Hit Cvent rate limit. Sleeping for .5 seconds...')
# time.sleep(.5)
# else:
# cvent_contact_list = cvent_contact_list + response_data.get('data')
# if 'paging' in response_data:
# next_token = response_data.get('paging').get('nextToken')
# log.debug(json.dumps(response_data.get('paging'), indent=2, default=str))
# log.warning('Sleeping for .25 seconds to avoid Cvent rate limit...')
# time.sleep(.25)
# else:
# next_token = None
# log.debug(json.dumps(cvent_contact_list, indent=2, default=str))
# log.debug(json.dumps(response_data, indent=2, default=str))
if 'message' in response_data and response_data['message'] == 'Too Many Requests': return False
return cvent_contact_list
# ### END ### API External Cvent Methods ### get_recent_contact_list() ###
# ### BEGIN ### API External Cvent Methods ### get_contact_id() ###
# Updated 2022-02-01
@logger_reset
def get_contact_id(contact_id: str):
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
get_access_token()
endpoint = f'/contacts/{contact_id}'
uri = api['base_url']+endpoint
params = {}
resp = requests.get(url=uri, headers=api['headers'], params=params)
response_data = resp.json()
log.debug(json.dumps(response_data, indent=2, default=str))
if 'message' in response_data and response_data['message'] == 'Too Many Requests': return False
return response_data
# ### END ### API External Cvent Methods ### get_contact_id() ###
# ### BEGIN ### API External Cvent Methods ### modify_contact_id() ###
# Updated 2022-02-01
@logger_reset
def modify_contact_id(contact_id: str, field_list: list=[], custom_field_id: str=None, custom_field_value: str=None):
log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
get_access_token()
if custom_field_id:
log.info(f'Updating Cvent Custom Field ID: {custom_field_id}')
endpoint = f'/contacts/{contact_id}/custom-fields/{custom_field_id}/answers'
elif field_list:
log.info(f'Updating Cvent Field List: {field_list}')
endpoint = f'/contacts/{contact_id}'
else:
log.error('Missing required parameters')
return False
uri = api['base_url']+endpoint
params = {}
data = {}
if custom_field_id:
data['id'] = custom_field_id
data['value'] = custom_field_value
else:
data = field_list
data['id'] = contact_id
try_request = True
limit = 0
while try_request and limit < 3:
limit = limit + 1
if custom_field_id:
resp = requests.put(url=uri, headers=api['headers'], params=params, json=data)
else:
resp = requests.patch(url=uri, headers=api['headers'], params=params, json=data)
response_data = resp.json()
log.debug(json.dumps(response_data, indent=2, default=str))
if 'message' in response_data and response_data['message'] == 'Too Many Requests':
log.warning('Hit Cvent rate limit. Sleeping for .5 seconds...')
time.sleep(.5)
else:
log.info('Updated Cvent Contact ID: {contact_id}')
try_request = False
# log.info('Updated Cvent Contact ID: {contact_id}')
# response_data = resp.json()
# log.debug(json.dumps(response_data, indent=2, default=str))
if 'message' in response_data and response_data['message'] == 'Too Many Requests': return False
return response_data
# ### END ### API External Cvent Methods ### modify_contact_id() ###
# ### BEGIN ### API External Cvent Methods ### create_update_aether_person() ###
# Updated 2022-02-02
@logger_reset
def create_update_aether_person(
cvent_contact_id: str,
cvent_contact_obj: dict,
account_id: str,
person_id: str = None,
idaa_refresh_person_group: bool = False,
log_lvl: int = logging.INFO, # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
):
log.setLevel(log_lvl)
# Important variables used more than once.
person_external_id = None
status = None
log.debug(cvent_contact_obj.get('customFields'))
if custom_field_list := cvent_contact_obj.get('customFields'): # List
for custom_field in custom_field_list:
# Get the External ID created by OSIT
if custom_field.get('id') == '609ab766-7d79-4a9d-a72c-f126412659ee':
# person_data['external_id'] = custom_field.get('value')[0]
person_external_id = custom_field.get('value')[0]
# Get the (Contact) Status created by OSIT
if custom_field.get('id') == 'e4e51781-e1ec-4f61-8329-b5d29bec6886':
# person_data['external_id'] = custom_field.get('value')[0]
status = custom_field.get('value')[0].lower()
log.debug(f'Cvent Customer Custom Status: {status}')
if status: pass
else: status = 'unknown' # Will try to improve this guess in membership section below
log.debug(status)
email = cvent_contact_obj.get('email')
membership_person_id = None
membership_person_type_id = None
person_data = {}
person_data['external_id'] = person_external_id
person_data['external_sys_id'] = cvent_contact_obj.get('sourceId')
# person_data['pronouns'] = ???
person_data['informal_name'] = cvent_contact_obj.get('nickname')
person_data['title_names'] = cvent_contact_obj.get('prefix')
person_data['given_name'] = cvent_contact_obj.get('firstName')
person_data['middle_name'] = cvent_contact_obj.get('middleName')
person_data['family_name'] = cvent_contact_obj.get('lastName')
person_data['designations'] = cvent_contact_obj.get('designation')
person_data['professional_title'] = cvent_contact_obj.get('title')
person_data['affiliations'] = cvent_contact_obj.get('company')
person_data['status'] = status
person_data['enable'] = True
log.debug(person_data)
contact_data = {}
contact_data['email'] = cvent_contact_obj.get('email')
contact_data['cc_email'] = cvent_contact_obj.get('ccEmail')
contact_data['phone_mobile'] = cvent_contact_obj.get('mobilePhone')
contact_data['phone_home'] = cvent_contact_obj.get('homePhone')
contact_data['phone_office'] = cvent_contact_obj.get('workPhone')
log.debug(contact_data)
address_data = {}
if cvent_contact_obj.get('homeAddress'):
address_data['line_1'] = cvent_contact_obj.get('homeAddress').get('address1')
address_data['line_2'] = cvent_contact_obj.get('homeAddress').get('address2')
address_data['line_3'] = cvent_contact_obj.get('homeAddress').get('address3')
address_data['city'] = cvent_contact_obj.get('homeAddress').get('city')
address_data['state_province'] = cvent_contact_obj.get('homeAddress').get('region')
if cvent_contact_obj.get('homeAddress').get('countryCode') and cvent_contact_obj.get('homeAddress').get('regionCode'):
# NOTE: There needs to be a better fix for this. Why does Cvent include the 3 character country code only sometimes???
cvent_region_code = cvent_contact_obj.get('homeAddress').get('regionCode').replace('(AUS)', '')
country_subdivision_code = cvent_contact_obj.get('homeAddress').get('countryCode') +'-'+ cvent_region_code
address_data['country_subdivision_code'] = country_subdivision_code
address_data['postal_code'] = cvent_contact_obj.get('homeAddress').get('postalCode')
address_data['country_alpha_2_code'] = cvent_contact_obj.get('homeAddress').get('countryCode')
address_data['country'] = cvent_contact_obj.get('homeAddress').get('country')
address_data['country_alpha_2_code'] = cvent_contact_obj.get('homeAddress').get('countryCode')
log.debug(address_data)
contact_data['address'] = address_data
person_data['contact'] = contact_data
user_data = {}
# user_data['name'] =
user_data['username'] = cvent_contact_obj.get('email')
user_data['email'] = cvent_contact_obj.get('email')
# random_password_string = secrets.token_urlsafe(8)
# user_data['password'] = secure_hash_string(string=random_password_string)
user_data['email_verified'] = True # Assuming this is True because they came from another system where the email address is required.
user_data['enable'] = True
user_data['enable_from'] = datetime.datetime.now(datetime.timezone.utc)
user_data['enable_to'] = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=365)
user_data['super'] = False # This is just not allowed
user_data['manager'] = False # This is just not allowed
# user_data['administrator'] = False
user_data['public'] = False
user_data['verified'] = True
person_data['user'] = user_data
if cvent_contact_obj.get('type'):
# NOTE: Should this be renamed to contact_type_id and contact_type_name???
cvent_contact_type_id = cvent_contact_obj.get('type').get('id')
cvent_contact_type_name = cvent_contact_obj.get('type').get('name')
log.info(f'Found Cvent Contact Type Named: {cvent_contact_type_name}')
else:
cvent_contact_type_id = None
cvent_contact_type_name = None
# 'id': '5EB898D8-C253-482C-A93A-0B6667C26E04', 'name': 'Al-Anon Member'
# 'id': 'A20358C5-0F6C-47AF-9843-BA9483A9D767', 'name': 'Al-Anon Non-Member'
# 'id': 'A01900AB-496A-48A1-9B04-C2874651227E', 'name': 'Member'
# 'id': '65437A15-39C2-4EB5-9AFE-67AF6FE41C27', 'name': 'Non-Member'
# 'id': '03622AEE-F586-4AE5-A191-B8372543A8C8', 'name': 'Student Member'
# 'id': 'A69FAF20-BF2A-4222-B15B-7B0C7EFBEAA7', 'name': 'Student Non-member'
# 'id': '54127B4D-E531-4046-AF5C-0F0D71DC39D2', 'name': 'Adult Guest Registration'
# 'id': 'C9FA7E47-A925-44AB-B94A-9B3003CA2AC4', 'name': 'Attendee'
# 'id': '6F06D6B6-2C23-4EF8-986F-73BF0DB2B229', 'name': "Children's Program with Jerry Moe (7-12 years)"
# 'id': 'AADABEF0-3C84-45A2-9D9B-E2CF585D4AE5', 'name': 'General Attendee'
# 'id': '96D5B3CC-FD4E-4957-BA71-9CEF388095EF', 'name': 'Guest'
# 'id': '71D07118-C24D-4B2E-888D-56AC1B941495', 'name': "IDAA 20's Guest Registration"
# 'id': 'DA17F721-9924-43E3-A31F-C567BA96DC64', 'name': 'IDAA Teen (13-19 years)'
# 'id': 'C49439B3-5AE6-496F-A0AD-4CCB1A9000E3', 'name': 'Spouse/SO Guest Registration'
# Currently in use Member Type names for IDAA:
# Member Type = Member Contact Type
# Al-Anon Member(s) = "Al-Anon Member" and "Al-Anon Non-Member"
# Annual Contribution(s) = "Attendee" and "Non-Member"
# Doctoral Qualifying Member(s) = "Member" and "Non-Member"
# Student Member(s) = "Student Member" and "Student Non-member"
# NOTE: "Student Non-member" is NOT "Student Non-Member" (the lowercase m)
membership_person_data = {}
membership_person_type_data = {}
# if cvent_contact_type_name:
if cvent_contact_obj.get('membership'):
if cvent_contact_type_name == 'Al-Anon Member' or cvent_contact_type_name == 'Al-Anon Members':
membership_person_type_data['membership_type_id'] = 6
membership_person_type_data['product_id'] = 13
membership_person_type_data['level'] = 1
elif cvent_contact_type_name == 'Annual Contribution' or cvent_contact_type_name == 'Annual Contributions' or cvent_contact_type_name == 'Attendee': # Unsure... making affiliate
membership_person_type_data['membership_type_id'] = 8
membership_person_type_data['product_id'] = 13
membership_person_type_data['level'] = 3
elif cvent_contact_type_name == 'Doctoral Qualifying Member' or cvent_contact_type_name == 'Doctoral Qualifying Members' or cvent_contact_type_name == 'Member':
membership_person_type_data['membership_type_id'] = 5
membership_person_type_data['product_id'] = 4
membership_person_type_data['level'] = 1
elif cvent_contact_type_name == 'Student Member' or cvent_contact_type_name == 'Student Members':
membership_person_type_data['membership_type_id'] = 7
membership_person_type_data['product_id'] = 14
membership_person_type_data['level'] = 1
elif cvent_contact_type_name in ['Al-Anon Non-Member', 'Non-Member', 'Student Non-member', 'Student Non-Member']:
membership_person_type_data['membership_type_id'] = 8
membership_person_type_data['product_id'] = 13
membership_person_type_data['level'] = 3
else:
log.error(f'Unknown Contact Type Name from Cvent: {cvent_contact_type_name}')
cvent_contact_type_id = None
cvent_contact_type_name = None
membership_person_type_data['first_start_on'] = datetime.datetime.strptime(cvent_contact_obj.get('membership').get('joined'), '%Y-%m-%d')
if cvent_contact_obj.get('membership').get('lastRenewal'):
membership_person_type_data['start_on'] = datetime.datetime.strptime(cvent_contact_obj.get('membership').get('lastRenewal'), '%Y-%m-%d')
else:
membership_person_type_data['start_on'] = datetime.datetime.strptime(cvent_contact_obj.get('membership').get('joined'), '%Y-%m-%d')
membership_person_type_data['end_on'] = datetime.datetime.strptime(cvent_contact_obj.get('membership').get('expiration'), '%Y-%m-%d')
membership_person_type_data['last_end_on'] = datetime.datetime.strptime(cvent_contact_obj.get('membership').get('expiration'), '%Y-%m-%d')
current_datetime = datetime.datetime.now()
# log.debug(status)
# if status == 'unknown':
# log.debug(current_datetime)
# buffer_datetime = current_datetime - datetime.timedelta(minutes=1440) # 720 min = 12 hours
# log.debug(buffer_datetime)
# log.debug(membership_person_type_data['first_start_on'])
# log.info('Status is unknown. Going to try and make a guess...')
# if membership_person_type_data['first_start_on'] < buffer_datetime and membership_person_type_data['end_on'] >= current_datetime:
# person_data['status'] = 'approved' # approved and current
# elif membership_person_type_data['first_start_on'] < current_datetime and membership_person_type_data['end_on'] < current_datetime:
# person_data['status'] = 'approved' # approved but expired
# else:
# person_data['status'] = 'pending' # likely new?
# log.debug(person_data['status'])
if membership_person_type_data['end_on'] >= current_datetime:
membership_person_type_data['lu_membership_type_status_id'] = 5 # 5 = active; expiration is > now
else:
membership_person_type_data['lu_membership_type_status_id'] = 7 # 7 = inactive; expiration is < now
membership_person_data['enable'] = True
membership_person_type_data['enable'] = True
membership_person_data['membership_person_type'] = membership_person_type_data
# log.debug(json.dumps(membership_person_data, indent=2, default=str))
# Try to look up using external ID
if not person_id and person_external_id:
log.info(f'Looking up person with External ID: {person_external_id}')
if result := get_person_rec_w_external_id(account_id=account_id, external_id=person_external_id):
log.debug(result)
person_id = result.get('person_id')
log.info(f'Person ID {person_id} found using external ID.')
else: pass
# If that fails then try to look up using email address
if not person_id and email:
log.info(f'Looking up person with Email Address: {email}')
if result := get_person_rec_list(for_obj_type='account', for_obj_id=account_id, email=email):
log.debug(result[0])
person_id = result[0].get('person_id')
log.info(f'Person ID {person_id} found using email address.')
else: pass
log.debug(f'Person ID: {person_id}; External ID: {person_external_id}; Email: {email}')
# ### TESTING BREAK POINT ###
# person_data['membership_person'] = membership_person_data
# return False
# ### TESTING BREAK POINT ###
# If there is not an external ID for an existing or new person then one needs to be created.
if not person_external_id:
N = 8
random_string = ''.join(random.choices(string.ascii_uppercase + string.digits, k=N))
random_string = ''.join(random.SystemRandom().choices(string.ascii_uppercase + string.digits, k=N))
# random_string = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))
log.info(f'Created random string: {random_string}')
email = cvent_contact_obj.get('email')
person_external_id = f'{random_string}~{email}'
log.info(f'Created new Person External ID: {person_external_id}')
person_data['external_id'] = person_external_id
# NOTE: Update Cvent Contact
custom_field_id = '609ab766-7d79-4a9d-a72c-f126412659ee' # IDAA Cvent External ID UUID
custom_field_value = [person_external_id]
log.warning('Sleeping for .5 seconds to avoid Cvent rate limit...')
time.sleep(.5)
contact_mod_result = modify_contact_id(
contact_id = cvent_contact_id, # This is the Cvent Contact UUID for a person
# field_list = field_list,
custom_field_id = custom_field_id,
custom_field_value = custom_field_value,
)
if person_id:
# ### SECTION ### Load person object to populate the person_data and membership_person_data dicts.
person_obj = load_person_obj(person_id=person_id, inc_address=True, inc_contact=True, inc_membership_person=True, inc_membership_person_type=True, inc_user=True)
log.debug(person_obj)
person_data['id'] = person_id
person_data['account_id'] = account_id
person_data['contact']['id'] = person_obj.contact.id
person_data['contact']['address']['id'] = person_obj.contact.address.id
if person_obj.user:
person_data['user']['id'] = person_obj.user.id
if person_obj.membership_person:
membership_person_id = person_obj.membership_person.id
if person_obj.membership_person.membership_person_type:
membership_person_type_id = person_obj.membership_person.membership_person_type.id
else: membership_person_type_id = None
if not person_obj.external_id:
person_data['external_id'] = person_external_id
log.debug(person_data)
if update_person_kiss(person_id=person_id, person_dict_obj=person_data, set_default_password=False):
log.info(f'Updated Person ID: {person_id}')
else:
log.info(f'Did not update Person ID: {person_id}')
else:
# ### SECTION ### Create new person and related with the person_data and membership_person_data dicts.
person_data['account_id'] = account_id
person_data['notes'] = 'Created using data from Cvent'
random_password_string = secrets.token_urlsafe(8)
person_data['user']['password'] = secure_hash_string(string=random_password_string)
user_data['notes'] = 'Created using data from Cvent'
# other_data = {}
# other_data['temp_password'] = random_password_string
# person_data['user']['other_json'] = json.dumps(other_data, indent=4)
log.debug(person_data)
if create_person_obj_result := create_person_kiss(account_id=account_id, person_dict_obj=person_data):
person_id = create_person_obj_result
log.info(f'Created Person ID: {person_id}')
else:
log.info(f'Did not create Person')
# ### TESTING BREAK POINT ###
# person_data['membership_person'] = membership_person_data
# return False
# ### TESTING BREAK POINT ###
if cvent_contact_obj.get('membership'):
if cvent_contact_type_id and membership_person_id:
# membership_person_id = person_obj.membership_person.id
membership_person_data['id'] = membership_person_id
membership_person_data['membership_person_type']['id'] = membership_person_type_id
if update_membership_person_obj(membership_person_id=membership_person_id, membership_person_dict_obj=membership_person_data):
log.info(f'Updated Membership Person ID: {membership_person_id}')
else:
log.info(f'Did not update Membership Person ID: {membership_person_id}')
elif cvent_contact_type_id:
if create_membership_person_obj_result := create_membership_person_obj(account_id=account_id, person_id=person_id, membership_person_dict_obj=membership_person_data):
membership_person_id = create_membership_person_obj_result
log.info(f'Created Membership Person ID: {membership_person_id}')
else:
log.info(f'Did not create Membership Person')
else:
membership_person_data = {}
else:
membership_person_data = {}
person_data['membership_person'] = membership_person_data
log.debug(json.dumps(person_data, indent=2, default=str))
if idaa_refresh_person_group:
refresh_person_group(person_id=person_id)
# person_obj = load_person_obj(person_id=person_id, inc_address=True, inc_contact=True, inc_membership_person=True, inc_membership_person_type=True, inc_user=True)
# log.debug(person_obj)
return person_id # True
# ### END ### API External Cvent Methods ### create_update_aether_person() ###