"""Lambda altafonte-create-user function module.""" import dataclasses import re import textwrap from typing import Any import config from src import constants, types def handler(event: Any, context: Any) -> dict[str, str]: """Lambda entry point.""" try: input = create_identity_mutation_input(event) query = textwrap.dedent(""" mutation createIdentityV2( $identity: IdentityInput!, $tenantProfileRoles: TenantProfileRolesCreateInput!, $masterContact: Boolean, $sendInvite: Boolean ) { createIdentity( identity: $identity, tenantProfileRoles: $tenantProfileRoles masterContact: $masterContact, sendInvite: $sendInvite ) { id } } """) result = config.ows_client.post( 'graphql-router', '/graphql', json={ 'operationName': 'createIdentityV2', 'query': query, 'variables': dataclasses.asdict(input), }, headers=constants.HEADERS, ) result_data = result.json()['data'] if not result_data: raise RuntimeError(f'Error creating identity: {result.json().get("errors")}') return dataclasses.asdict( types.HandlerOutput( email=event['email'], send_email=event['send_email'], identity_id=result_data['createIdentity']['id'], ) ) except Exception as e: config.logger.exception(str(e)) raise e def create_identity_mutation_input(event: Any) -> types.CreateIdentityMutationInput: """Take an event and turn it into input for the createIdentity mutation.""" identity_input = types.IdentityInput( email=event.get('email'), firstName=event.get('first_name'), lastName=event.get('last_name'), ) tenant_profile_roles_input = types.TenantProfileRolesInput( tenantUuid=_validated_uuid(event.get('tenant_uuid')), tenantType=_get_tenant_type(event.get('tenant_type')), rolesToAttach=_event_to_v2_roles(event), ) return types.CreateIdentityMutationInput( identity=identity_input, tenantProfileRoles=tenant_profile_roles_input, masterContact=_yn_to_bool(event.get('is_master_contact')), sendInvite=_yn_to_bool(event.get('send_email')), ) def _validated_uuid(uuid_str: str) -> str: uuid_regex = re.compile( r'^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$' ) lowered_uuid_str = uuid_str.lower() if not uuid_regex.match(lowered_uuid_str): raise RuntimeError(f'Invalid uuid: {lowered_uuid_str}') return lowered_uuid_str def _event_to_v2_roles(event: Any) -> list[str]: total_roles: list[str] = [] for field_name, roles in constants.CSV_FIELDS_TO_V2_ROLES_MAP.items(): if event.get(field_name).upper() == 'Y': total_roles += roles return total_roles def _get_tenant_type(tenant_type: str) -> str: mapped_tenant_type: str | None = constants.TENANT_TYPE_MAPPING.get(tenant_type) if not mapped_tenant_type: raise RuntimeError(f'Invalid tenant type: {tenant_type}') return mapped_tenant_type def _yn_to_bool(yn: str) -> bool: return yn.upper() == 'Y'