o
    pjd                  '   @  s  d Z ddlmZ ddlmZmZ ddlZejdZedur'e	eds'ejd= ddl
mZmZmZmZmZ ddlmZmZ dd	lmZmZ dd
lmZ ddlmZmZ ddlmZmZ ddlmZ ddl m!Z!m"Z"m#Z# ddl$m%Z%m&Z& ddl'm(Z(m)Z) dZ*eddddedddddedddded d!d"ded#d$d%ded&d'd(ded)d*d+d,d-d.fed/d0d1g d2d3d4d5ed6d7d1d,d8d1g d9d3e*d:d;d<d=ed>d?d1d,d8d1d@dAgd3dBdBdCdDdEdF	edGdHd1d,d8d1g dId3dJd;d4dKedLdMd1g dNd3dOdPdQedRdSd1d,g dTdUd1dVgd3dBdBdCdDdWdF	edXdYd1dZgd3d1dZd[gd3dOd\d]ed^d_d1dZgd3d1dZd[gd3dBdBd`dDdadF	edbdcd1dZddgd3d1dZd[gd3dBd,dBd`dDdedf
edgdhd1dZgd3d1dZd[gd3dBdBd:dDdadF	edidjd1d,dkdlidkdlidkd1idmdndogidpdqd1g drd3e*dsdOdtedBdudvdwdxdydzd{d|d}d~
d	eddd1d,dgddddmdndogiddd1g dd3e*d:dOdedBdddwdddzd{d|d}d~
d	eddd1d,dgdldd:ddkdlidkd1idmdndogidpdd1g drd3e*dsdOdtedBddddddzd{d|d}d~
d	deddddddddZ+dd Z,dd Z-dd Z.dd Z/dd Z0dd Z1dd Z2dd Z3dd Z4dddZ5dddZ6dddZ7dddZ8d,dddZ9dd Z:dS )z=Platform App Standard v1 entrypoint for the AroFlo connector.    )annotations)datetimetimezoneNplatform__path__)ActionContractAgentCapabilityContractAppManifestCredentialFieldWordPressPackageContract)error_envelopesuccess_envelope)SecretConfigurationErrorSecretIntegrityError)SecretsManager   )AroFloClientAroFloError)AroFloConfigErrorAroFloSettings)build_capabilities_manifest)bot_pool_summaryconfigure_bot	list_bots)AroFloWorkerClientWorkerError)UsersContractErrorquery_users)aroflo_base_urlaroflo_u_encodedaroflo_p_encodedaroflo_api_secretaroflo_org_encodedaroflo_connector_appzAroFlo Connectorz	1.5.0-devzNConnect the platform to AroFlo through API-first and controlled UI transports.r   zAroFlo API base URLurlzThe tenant AroFlo API endpoint.)kind	help_textr   zAroFlo encoded userz$The API user value issued by AroFlo.)r&   r    zAroFlo encoded passwordz(The API password value issued by AroFlo.r!   zAroFlo API secretz)The HMAC signing secret issued by AroFlo.r"   zAroFlo encoded organizationz,The API organization value issued by AroFlo.aroflo_host_ipzAroFlo API host IPtextFz4Optional source IP included in the AroFlo signature.)r%   requiredr&   platform.healthzEReport local connector and vault readiness without contacting AroFlo.objecthealthyvault_readyapi_credentials_configuredprovider_checked)typer)    )
capabilitydescriptionoutput_schemaerrorsplatform.credentials.testzHValidate tenant API credentials with a minimal read-only AroFlo request.)r1   additionalProperties	connectedprovider	transport	tested_at   internal)tenant_context_missingcredential_not_configuredcredential_vault_unavailableprovider_connection_failed)r3   r4   input_schemar5   required_credentialstimeout_secondsdata_classificationr6   aroflo.api.configurezGStore tenant-scoped AroFlo API credentials as write-only vault secrets.
configuredfieldsT
   
restricted)r@   invalid_inputrB   )	r3   r4   rD   r5   side_effects
idempotentrF   rG   r6   aroflo.catalog.readzKList registered AroFlo zones and operation metadata without executing them.zones
zone_countoperation_countr0      )r3   r4   rD   r5   rF   rG   r6   aroflo.bots.listz1List safe tenant BOT profiles and assigned zones.)botsrI   r:   confidential)r@   )r3   r4   r5   rG   r6   aroflo.bot.configurezGCreate or update one tenant BOT profile and its write-only credentials.)bot_idlabelrR   )r1   r8   r)   bot)r@   rM   bot_configuration_failedaroflo.bot.statusz6Return the safe live session state for one tenant BOT.rZ   state)rM   bot_not_foundworker_unavailable)r3   r4   rD   r5   rG   r6   aroflo.bot.connectzDStart or resume an authenticated AroFlo browser session for one BOT.Z   )rM   r`   bot_busyra   aroflo.bot.mfa.submitzESubmit one ephemeral MFA challenge response to an active BOT session.code)rM   r`   rd   mfa_rejectedra   )
r3   r4   rD   r5   rN   rO   idempotency_key_requiredrF   rG   r6   aroflo.bot.disconnectzHClose one BOT browser session while preserving encrypted reusable state.aroflo.users.listzEList normalized AroFlo users with allowlisted filters and pagination.r1   arrayenumautoapi)filterssort
paginationr<   )r1   r8   
properties)outcomeitemsrq   meta   )rM   unsupported_filtertransport_unavailablerA   provider_unavailablezList AroFlo usersz?List normalized AroFlo users using safe filters and pagination.)aroflousers)z@The user asks for AroFlo users or staff matching known criteria.)z=The request changes a user or concerns non-AroFlo identities.readlownever)zaroflo.users.read)
exposedtitlesummarydomainsuse_whendo_not_use_whenrisk_category
risk_levelconfirmationrequired_permissions)	r3   r4   rD   r5   rE   rF   rG   r6   agentaroflo.users.getz4Get one normalized AroFlo user by canonical user ID.	record_idstring)r1   	minLength)r   r<   )r1   r8   r)   rr   )rs   itemru   )rM   rx   rA   ry   zGet an AroFlo userzDRetrieve one normalized AroFlo user from an exact canonical user ID.)z!An exact AroFlo user ID is known.)z;Only a name or email is available; use user search instead.aroflo.users.searchzDSearch normalized AroFlo users with one or more allowlisted filters.ro   )r1   minItemsmaxItemszSearch AroFlo userszQResolve AroFlo users by name, email, username, phone, position, status, or dates.)rz   r{   identity_resolution)zWThe user identifies AroFlo staff by name, email, phone, position, or combined criteria.)zThe request changes user data.)	health_v1test_connection_v1configure_api_v1zones_v1bots_v1configure_bot_v1bot_status_v1connect_bot_v1submit_bot_mfa_v1disconnect_bot_v1users_list_v1users_get_v1users_search_v1aroflo_connector_wpz"wordpress-pack/aroflo-connector-wpzaroflo-connector-wp.phpz+aroflo-connector-wp/aroflo-connector-wp.php)r*   r7   rH   rP   rV   rY   r^   rb   re   ri   rj   r   r   )
package_idversionsource_directory
entrypointplugin_filecapabilities)app_iddisplay_nameapp_versionr4   credentialsactionswordpress_packagec                 C  s   |dkrt | S |dkrt| S |dkrt| S |dkr t| S |dkr(t| S |dkr0t| S |dv r9t| |S |dv rBt| |S tt	j
|t| d	d
ddfS )zGDispatch Standard v1 actions while legacy entrypoints remain available.r   r   r   r   r   r   >   r   r   r   r   >   r   r   r   action_not_foundz&The requested action is not supported.)r   action
request_idrf   message  )_health_test_connection_configure_api_zones_bots_configure_bot_bot_session_action_users_readr   APP_MANIFESTr   _request_id)contextr   r2   r2   %apps/aroflo_connector_app/__init__.pyhandle_request  s2   

r   c              	   C  s\   d}d}t | }|rzt|}W n ttfy   d}Y nw ttjdt| d||dddS )NFTr   r,   r   r   r   data)
_tenant_id_api_credentials_configuredr   r   r   r   r   r   )r   rI   r.   	tenant_idr2   r2   r   r   4  s&   r   c                 C  s   t | }|st| ddddS z	tt|}W n% ty(   t| dddd Y S  ttfy<   t| ddd	d
dd Y S w zt|dj	ddddgt
|jdd W n tyd   t| dddddd Y S w ttjdt| dddttj ddS )Nr   r@   %A trusted tenant context is required.  rA   :AroFlo API credentials are not configured for this tenant.  rB   z0The credential vault is temporarily unavailable.  T	retryablesettings GET)zone
lastupdate)page1r>   )methodparamstimeoutrC   z.AroFlo API credentials could not be validated.  AroFlorn   r9   r   )r   _errorr   from_credentials_load_api_credentialsr   r   r   r   requestminr   r   r   r   r   r   r   nowr   utc	isoformat)r   r   r   r2   r2   r   r   J  sp   






r   c                   s.  t | }|st| ddddS | pi dpi  td } fdd|D fd	d
tD }|r7t| ddddS d  dsHt| ddddS z$t } D ]\}}|rj|j|t	j
||t| pai dpfdd qPW n ttttfy   t| dddd Y S w tt	j
dt| ddd  D ddS )Nr   r@   r   r   payloadr'   c                   s$   i | ]}|t  |pd  qS )r   )strgetstrip.0name)r   r2   r   
<dictcomp>  s   $ z"_configure_api.<locals>.<dictcomp>c                   s   g | ]} | s|qS r2   r2   r   )valuesr2   r   
<listcomp>  s    z"_configure_api.<locals>.<listcomp>rM   z5All required AroFlo API credentials must be supplied.r   zhttps://z"The AroFlo API URL must use HTTPS.subjectr   )r   r   secret_namesecret_valueactor_idrB   z1The API credentials could not be stored securely.r   Tc                 S  s   i | ]	\}}|t |qS r2   )bool)r   r   valuer2   r2   r   r     s    )rI   rJ   r   )r   r   r   API_CREDENTIAL_NAMESlower
startswithr   rt   
put_secretr   r   r   
ValueErrorLookupErrorr   r   r   r   )r   r   allowedmissingmanagerr   r   r2   )r   r   r   r     sL   
r   c              	   C  s   t t }g }d}|dg D ])}dd |dg D }|t|7 }||dd|dd|d	d|d
 qttjdt| |t||ddddidS )Nr   rR   c                 S  sb   g | ]-}| d d| dd| dd| dd| ddt| ddt| d	d
d
dqS )rf   r   r[   r4   http_methodside_effectr|   rO   Trequires_confirmationF)rf   r[   r4   r   accessrO   r   	published)r   r   )r   	operationr2   r2   r   r     s    




z_zones.<locals>.<listcomp>
operationsrf   r   r[   r4   )rf   r[   r4   r   r   FrQ   execution_enabled)r   r   r   r   ru   )	r   r+   r   lenappendr   r   r   r   )r   manifestrR   rT   r   r   r2   r2   r   r     s4   




r   c                 C  s:   t | }|st| ddddS t|}ttjdt| |dS )Nr   r@   r   r   r   )r   r   r   r   r   r   r   )r   r   r   r2   r2   r   r     s   r   c                 C  s   t | }|st| ddddS | pi dpi }z:t||dd|dd|d	d|d
d|dp4g |dd|dd|ddt| pGi dpLdd
}W n ttfyd   t| dddd Y S w ttj	dt
| d|idS )Nr   r@   r   r   r   rZ   r   r[   usernamepasswordrR   base_urlenabledTremember_30_daysFr   r   )	rZ   r[   r  r  rR   r  r  r	  r   rM   z(The BOT profile could not be configured.r\   r   )r   r   r   r   r   r   r   r   r   r   r   )r   r   r   r\   r2   r2   r   r     s&   



r   c                   s  t | | pi dpi }}t|dpd   |r s't| |dddS t fddt|D s<t| |d	d
dS ddi dfddi dfddi dfd}|dkrt|dpYd }t|dksl|	 rl|dstt| |dddS t
 fddt|D }dd|t|dddf\}}}	}
n|| \}}}	}
zt j||| |	|
d}W n' ty } z|jdkrd nd!}t| ||jd"||jd#W  Y d }~S d }~ww t|d$pd% }ttj|t|  |d&d'S )(Nr   rZ   r   rM   zA valid BOT ID is required.r   c                 3  s$    | ]}|d   ko|d V  qdS )rZ   r  Nr2   r   r\   rZ   r2   r   	<genexpr>  s   " z&_bot_session_action.<locals>.<genexpr>r`   zThe BOT profile is unavailable.r   r   z/ui/session/status   POSTz/ui/session/connectrc   z/ui/session/closer>   )r   r   r   r   rf      idempotency_keyz6A six-digit MFA code and idempotency key are required.c                 3  s     | ]}|d   kr|V  qdS )rZ   Nr2   r
  r  r2   r   r    s    z/ui/session/mfar	  )rf   r	  )r   rZ   r   r   rd   r   r   z.The BOT worker could not complete the request.r   r_   unknown)rZ   r_   r   )r   r   r   r   r   r   anyr   r  isdigitnextr   r   callr   rf   r   r   r   r   r   )r   r   r   r   mappingrf   r\   r   pathworker_payloadr   resultexcstatusr_   r2   r  r   r     sH   



r   c                 C  s   t | }|st| |dddS t| pi dpi }dddd| |d	< ztt|}tt|d
|}W n? t	yE   t| |ddd Y S  t
ya } zt| ||jt|dW  Y d }~S d }~w tys   t| |ddddd Y S w ttj|t| |dS )Nr@   r   r   r   listr   search)r   r   r   r   r   rA   r   r   ry   z*AroFlo could not complete the users query.r   Tr   r   )r   r   dictr   r   r   r   r   r   r   r   rf   r   r   r   r   r   r   )r   r   r   r   r   r   r  r2   r2   r   r     s4   "
r   r   r   returndict[str, str]c                   s$   t   td } fdd|D S )Nr   c                   s,   i | ]} j tj|d  dur|qS ))r   r   r   N)
get_secretr   r   r   r   r   r   r2   r   r   '  s    z)_load_api_credentials.<locals>.<dictcomp>)r   r   )r   namesr2   r"  r   r   $  s
   r   r   c                   s   t |  t fddtD S )Nc                 3  s    | ]
}t  |V  qd S )N)r   r   r   r   r2   r   r  4  s    z._api_credentials_configured.<locals>.<genexpr>)r   allr   )r   r2   r$  r   r   2  s   r   c                 C  s    t | pi dp	i dpdS )Ntenantr   r   r   r   r   r2   r2   r   r   7  s    r   c                 C  s   t | pi dp	dS )Nr   r   r'  r(  r2   r2   r   r   ;  s   r   r   c                C  s   t tj|t| |||d|fS )N)r   r   r   rf   r   r   )r   r   r   r   )r   r   rf   r   r  r   r2   r2   r   r   ?  s   r   c                 C  s   ddl m} | j|dd dS )z@Register the legacy Flask blueprint during the migration window.r   )bpz/api/aroflo/v1)
url_prefixN)api.v1.blueprintr)  register_blueprint)apparoflo_v1_bpr2   r2   r   init_appJ  s   r/  )r   r   r  r   )r   r   r  r   )r  r   );__doc__
__future__r   r   r   sysmodulesr   loaded_platformhasattrbridge_platform.apps.contractsr   r   r	   r
   r   bridge_platform.apps.envelopesr   r   "bridge_platform.secrets.encryptionr   r   'bridge_platform.secrets.secrets_managerr   clientr   r   configr   r   services.capabilitiesr   bot_poolr   r   r   worker_clientr   r   services.users_v1r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r/  r2   r2   r2   r   <module>   s   	$	


		
	

  1  r< )	"



