import logging
from typing import Optional
from hashlib import md5
from uuid import UUID
from lxml import etree
from q2_sdk.models.demographic import Address, DemographicInfo, Phone, PhoneType
from .xml_helper import find_with_default
[docs]
class SSOUser:
"""
Object representation of the User inuser_nodeation that comes in on a
Q2 Online request
"""
def __init__(
self,
request_xml: Optional[etree.Element] = None,
request_json: Optional[dict] = None,
customer_key: Optional[str] = None,
):
"""
:param request_xml: XML node from Q2 Online request
"""
self.logger = logging.getLogger("q2_sdk.general")
self.user_id = None
self.user_guid = None
"""A consistent ID for this user guaranteed to be unique across databases. Useful for multitenant extensions"""
self.login_name = None
self.first_name = None
self.middle_name = None
self.last_name = None
self.ssn = None
self.email_address = None
self.city = None
self.state = None
self.postal_code = None
self.home_phone = None
self.work_phone = None
self.home_country = None
self.work_country = None
self.address1 = None
self.address2 = None
self.demographic_info: Optional[DemographicInfo] = None
self.customer_primary_cif = None
self.dob: Optional[str] = None
"""This value is not present in the incoming request from HQ so it has to be
set manually if needed. You can use the get_user_dob method provided in online form extensions"""
if request_xml is not None:
self._hydrate_from_xml(request_xml)
elif request_json is not None:
self._hydrate_from_json(request_json)
if customer_key is not None:
self.user_guid = self._get_user_guid(customer_key)
@property
def demographic_info(self) -> DemographicInfo:
self.logger.warning(
"OnlineUser.demographic_info has been deprecated. Please use .as_demographic_info() instead."
)
return self.as_demographic_info()
@demographic_info.setter
def demographic_info(self, value: DemographicInfo):
self._demographic_info = value
def _hydrate_from_xml(self, request_xml: etree.Element):
user_node = request_xml.find(".//{*}Q2_UserInfoView")
for elem in user_node.getiterator():
elem.tag = etree.QName(elem).localname
etree.cleanup_namespaces(user_node)
self.user_id = find_with_default(user_node, "UserID", data_type=int)
self.login_name = find_with_default(user_node, "LoginName", data_type=str)
self.first_name = find_with_default(user_node, "FirstName", data_type=str)
self.middle_name = find_with_default(user_node, "MiddleName", default="")
self.last_name = find_with_default(user_node, "LastName", data_type=str)
self.ssn = find_with_default(user_node, "SSN", data_type=str)
self.email_address = find_with_default(user_node, "EmailAddress")
self.city = find_with_default(user_node, "City")
self.state = find_with_default(user_node, "State")
self.home_country = find_with_default(user_node, "HomeCountryName")
self.work_country = find_with_default(user_node, "WorkCountryName")
self.postal_code = find_with_default(user_node, "PostalCode", data_type=str)
self.home_phone = None
self.work_phone = None
home_area_code = find_with_default(
user_node, "HomeAreaCode", default="", data_type=str
)
home_local_number = find_with_default(
user_node, "HomeLocalNumber", default="", data_type=str
)
home_extension = find_with_default(
user_node, "HomeExtension", default="", data_type=str
)
if all((home_area_code, home_local_number)):
self.home_phone = f"{home_area_code}{home_local_number}".strip()
if home_extension:
self.home_phone += f"x{home_extension}"
work_area_code = find_with_default(
user_node, "WorkAreaCode", default="", data_type=str
)
work_local_number = find_with_default(
user_node, "WorkLocalNumber", default="", data_type=str
)
work_extension = find_with_default(
user_node, "WorkExtension", default="", data_type=str
)
if all((work_area_code, work_local_number)):
self.work_phone = f"{work_area_code}{work_local_number}"
if work_extension:
self.work_phone += f"x{work_extension}"
self.address1 = find_with_default(user_node, "StreetAddress1")
self.address2 = find_with_default(user_node, "StreetAddress2")
self._demographic_info: Optional(DemographicInfo) = None
def _hydrate_from_json(self, request: dict):
self.user_id = int(request.get("UserID"))
self.login_name = request.get("LoginName")
self.first_name = request.get("FirstName")
self.middle_name = request.get("MiddleName", None)
self.last_name = request.get("LastName")
self.ssn = str(request.get("SSN"))
self.email_address = request.get("EmailAddress")
self.city = request.get("City")
self.state = request.get("State")
self.home_country = request.get("HomeCountryName")
self.work_country = request.get("WorkCountryName")
self.postal_code = str(request.get("PostalCode"))
self.address1 = request.get("StreetAddress1")
self.address2 = request.get("StreetAddress2")
self.home_phone = None
self.work_phone = None
home_area_code = request.get("HomeAreaCode")
home_local_number = request.get("HomeLocalNumber")
home_extension = request.get("HomeExtension")
work_area_code = request.get("WorkAreaCode")
work_local_number = request.get("WorkLocalNumber")
work_extension = request.get("WorkExtension")
if all((home_area_code, home_local_number)):
self.home_phone = f"{home_area_code}{home_local_number}".strip()
if home_extension:
self.home_phone += f"x{home_extension}"
if all((work_area_code, work_local_number)):
self.work_phone = f"{work_area_code}{work_local_number}"
if work_extension:
self.work_phone += f"x{work_extension}"
self._demographic_info: Optional(DemographicInfo) = None
def as_demographic_info(self) -> DemographicInfo:
if not self._demographic_info:
phone_list = []
if self.home_phone:
phone_list.append(
Phone.build_from_str(self.home_phone, PhoneType.PERSONAL)
)
if self.work_phone:
phone_list.append(
Phone.build_from_str(self.work_phone, PhoneType.BUSINESS)
)
self._demographic_info = DemographicInfo(
self.dob if self.dob else "",
[self.email_address],
phone_list,
[
Address(
self.address1,
self.address2,
self.city,
self.state,
self.postal_code,
)
],
self.first_name,
self.last_name,
self.ssn,
middle_name=self.middle_name,
primary_cif=self.customer_primary_cif,
)
return self._demographic_info
def _get_user_guid(self, customer_key: str) -> str:
user_hash = md5()
user_hash.update(customer_key.encode("utf-8"))
user_hash.update(str(self.user_id).encode("utf-8"))
user_guid = str(UUID(bytes=user_hash.digest(), version=4)).upper()
return user_guid
def __repr__(self):
return f"<Object SSOUser>: {self.demographic_info}"