5757from dispatch .plugins .dispatch_slack .case .messages import (
5858 create_case_message ,
5959 create_signal_engagement_message ,
60+ create_manual_engagement_message ,
6061)
6162from dispatch .plugins .dispatch_slack .config import SlackConversationConfiguration
6263from dispatch .plugins .dispatch_slack .decorators import message_dispatcher
7576 relative_date_picker_input ,
7677 resolution_input ,
7778 title_input ,
79+ participant_select ,
7880)
7981from dispatch .plugins .dispatch_slack .middleware import (
8082 action_context_middleware ,
@@ -147,6 +149,8 @@ def configure(config: SlackConversationConfiguration):
147149
148150 app .command (config .slack_command_update_case , middleware = middleware )(handle_update_case_command )
149151
152+ app .command (config .slack_command_engage_user , middleware = middleware )(handle_engage_user_command )
153+
150154
151155# Commands
152156
@@ -339,6 +343,105 @@ def handle_list_signals_command(
339343 )
340344
341345
346+ def handle_engage_user_command (
347+ ack : Ack ,
348+ body : dict ,
349+ client : WebClient ,
350+ context : BoltContext ,
351+ db_session : Session ,
352+ ) -> None :
353+ """Handles engage user command."""
354+ ack ()
355+
356+ case = case_service .get (db_session = db_session , case_id = context ["subject" ].id )
357+ default_engagement = "We'd like to verify your identity. Can you please confirm this is you?"
358+
359+ blocks = [
360+ Context (
361+ elements = [
362+ MarkdownText (
363+ text = "Accept the defaults or adjust as needed. Person to engage must already be a participant in the case."
364+ )
365+ ]
366+ ),
367+ participant_select (label = "Person to engage" , participants = case .participants ),
368+ description_input (label = "Engagement text" , initial_value = default_engagement ),
369+ ]
370+
371+ modal = Modal (
372+ title = "Engage user via MFA" ,
373+ submit = "Engage" ,
374+ blocks = blocks ,
375+ close = "Close" ,
376+ callback_id = "manual-engage-mfa" ,
377+ private_metadata = context ["subject" ].json (),
378+ ).build ()
379+
380+ client .views_open (
381+ trigger_id = body ["trigger_id" ],
382+ view = modal ,
383+ )
384+
385+
386+ @app .view (
387+ "manual-engage-mfa" ,
388+ middleware = [
389+ action_context_middleware ,
390+ db_middleware ,
391+ modal_submit_middleware ,
392+ ],
393+ )
394+ def engage (
395+ ack : Ack ,
396+ body : dict ,
397+ client : WebClient ,
398+ context : BoltContext ,
399+ db_session : Session ,
400+ form_data : dict ,
401+ ) -> None :
402+ """Handles the engage user action."""
403+ ack ()
404+
405+ if form_data .get (DefaultBlockIds .participant_select ):
406+ user_email = client .users_info (user = form_data [DefaultBlockIds .participant_select ]["value" ])[
407+ "user"
408+ ]["profile" ]["email" ]
409+ else :
410+ # TODO: log error
411+ return
412+
413+ if form_data .get (DefaultBlockIds .description_input ):
414+ engagement = form_data [DefaultBlockIds .description_input ]
415+ else :
416+ # TODO log error
417+ return
418+
419+ case = case_service .get (db_session = db_session , case_id = context ["subject" ].id )
420+
421+ user = client .users_lookupByEmail (email = user_email )
422+
423+ result = client .chat_postMessage (
424+ text = "Engaging user..." ,
425+ channel = case .conversation .channel_id ,
426+ thread_ts = case .conversation .thread_id if case .has_thread else None ,
427+ )
428+ thread_ts = result .data .get ("ts" )
429+
430+ blocks = create_manual_engagement_message (
431+ case = case ,
432+ channel_id = case .conversation .channel_id ,
433+ engagement = engagement ,
434+ user_email = user_email ,
435+ user_id = user ["user" ]["id" ],
436+ thread_ts = thread_ts ,
437+ )
438+ client .chat_update (
439+ blocks = blocks ,
440+ channel = case .conversation .channel_id ,
441+ ts = thread_ts ,
442+ )
443+
444+
342445def _draw_list_signal_modal (
343446 client : WebClient ,
344447 body : dict ,
@@ -1435,6 +1538,26 @@ def create_channel_button_click(
14351538 client .views_open (trigger_id = body ["trigger_id" ], view = modal )
14361539
14371540
1541+ @app .action (
1542+ CaseNotificationActions .user_mfa ,
1543+ middleware = [button_context_middleware , db_middleware , user_middleware ],
1544+ )
1545+ def user_mfa_button_click (
1546+ ack : Ack ,
1547+ body : dict ,
1548+ client : WebClient ,
1549+ context : BoltContext ,
1550+ db_session : Session ,
1551+ ):
1552+ return handle_engage_user_command (
1553+ ack = ack ,
1554+ body = body ,
1555+ client = client ,
1556+ context = context ,
1557+ db_session = db_session ,
1558+ )
1559+
1560+
14381561def ack_handle_create_channel_event (ack : Ack , case : Case ) -> None :
14391562 """Handles the case channel creation event."""
14401563 msg = (
@@ -2192,7 +2315,9 @@ def engagement_button_approve_click(
21922315 mfa_plugin = plugin_service .get_active_instance (
21932316 db_session = db_session , project_id = context ["subject" ].project_id , plugin_type = "auth-mfa"
21942317 )
2195- mfa_enabled = True if mfa_plugin and engagement .require_mfa else False
2318+
2319+ require_mfa = engagement .require_mfa if engagement else True
2320+ mfa_enabled = True if mfa_plugin and require_mfa else False
21962321
21972322 blocks = [
21982323 Section (text = "Confirm that this is expected and that it is not suspicious behavior." ),
@@ -2288,7 +2413,10 @@ def handle_engagement_submission_event(
22882413 mfa_plugin = plugin_service .get_active_instance (
22892414 db_session = db_session , project_id = context ["subject" ].project_id , plugin_type = "auth-mfa"
22902415 )
2291- mfa_enabled = True if mfa_plugin and engagement .require_mfa else False
2416+
2417+ require_mfa = engagement .require_mfa if engagement else True
2418+ mfa_enabled = True if mfa_plugin and require_mfa else False
2419+
22922420 challenge , challenge_url = mfa_plugin .instance .create_mfa_challenge (
22932421 action = "signal-engagement-confirmation" ,
22942422 current_user = user ,
@@ -2299,8 +2427,12 @@ def handle_engagement_submission_event(
22992427 ack_mfa_required_submission_event (ack = ack , mfa_enabled = mfa_enabled , challenge_url = challenge_url )
23002428
23012429 case = case_service .get (db_session = db_session , case_id = metadata ["id" ])
2302- signal_instance = signal_service .get_signal_instance (
2303- db_session = db_session , signal_instance_id = UUID (metadata ["signal_instance_id" ])
2430+ signal_instance = (
2431+ signal_service .get_signal_instance (
2432+ db_session = db_session , signal_instance_id = UUID (metadata ["signal_instance_id" ])
2433+ )
2434+ if metadata ["signal_instance_id" ]
2435+ else None
23042436 )
23052437 # Get context provided by the user
23062438 context_from_user = body ["view" ]["state" ]["values" ][DefaultBlockIds .description_input ][
@@ -2324,6 +2456,7 @@ def handle_engagement_submission_event(
23242456 signal_instance = signal_instance ,
23252457 user = user_who_clicked_button ,
23262458 view_id = body ["view" ]["id" ],
2459+ thread_id = context ["subject" ].thread_id ,
23272460 )
23282461 db_session .commit ()
23292462 return
@@ -2339,6 +2472,7 @@ def handle_engagement_submission_event(
23392472 signal_instance = signal_instance ,
23402473 user = user_who_clicked_button ,
23412474 view_id = body ["view" ]["id" ],
2475+ thread_id = context ["subject" ].thread_id ,
23422476 )
23432477
23442478
@@ -2347,12 +2481,13 @@ def send_engagement_response(
23472481 client : WebClient ,
23482482 context_from_user : str ,
23492483 db_session : Session ,
2350- engagement : SignalEngagement ,
2484+ engagement : SignalEngagement | None ,
23512485 engaged_user : str ,
23522486 response : str ,
2353- signal_instance : SignalInstance ,
2487+ signal_instance : SignalInstance | None ,
23542488 user : DispatchUser ,
23552489 view_id : str ,
2490+ thread_id : str ,
23562491):
23572492 if response == MfaChallengeStatus .APPROVED :
23582493 title = "Approve"
@@ -2395,19 +2530,26 @@ def send_engagement_response(
23952530 user_email = engaged_user ,
23962531 engagement_status = engagement_status ,
23972532 )
2398- client .chat_update (
2399- blocks = blocks ,
2400- channel = case .conversation .channel_id ,
2401- ts = signal_instance .engagement_thread_ts ,
2402- )
2403- resolve_case (
2404- case = case ,
2405- channel_id = case .conversation .channel_id ,
2406- client = client ,
2407- db_session = db_session ,
2408- context_from_user = context_from_user ,
2409- user = user ,
2410- )
2533+ if signal_instance :
2534+ client .chat_update (
2535+ blocks = blocks ,
2536+ channel = case .conversation .channel_id ,
2537+ ts = signal_instance .engagement_thread_ts ,
2538+ )
2539+ resolve_case (
2540+ case = case ,
2541+ channel_id = case .conversation .channel_id ,
2542+ client = client ,
2543+ db_session = db_session ,
2544+ context_from_user = context_from_user ,
2545+ user = user ,
2546+ )
2547+ else :
2548+ client .chat_update (
2549+ blocks = blocks ,
2550+ channel = case .conversation .channel_id ,
2551+ ts = thread_id ,
2552+ )
24112553
24122554
24132555def resolve_case (
@@ -2528,9 +2670,14 @@ def handle_engagement_deny_submission_event(
25282670 metadata = json .loads (body ["view" ]["private_metadata" ])
25292671 engaged_user = metadata ["user" ]
25302672 case = case_service .get (db_session = db_session , case_id = metadata ["id" ])
2531- signal_instance = signal_service .get_signal_instance (
2532- db_session = db_session , signal_instance_id = UUID (metadata ["signal_instance_id" ])
2673+ signal_instance = (
2674+ signal_service .get_signal_instance (
2675+ db_session = db_session , signal_instance_id = UUID (metadata ["signal_instance_id" ])
2676+ )
2677+ if metadata ["signal_instance_id" ]
2678+ else None
25332679 )
2680+
25342681 engagement = signal_service .get_signal_engagement (
25352682 db_session = db_session ,
25362683 signal_engagement_id = metadata ["engagement_id" ],
@@ -2551,6 +2698,10 @@ def handle_engagement_deny_submission_event(
25512698 channel = case .conversation .channel_id ,
25522699 thread_ts = case .conversation .thread_id ,
25532700 )
2701+
2702+ thread_ts = (
2703+ signal_instance .engagement_thread_ts if signal_instance else context ["subject" ].thread_id
2704+ )
25542705 blocks = create_signal_engagement_message (
25552706 case = case ,
25562707 channel_id = case .conversation .channel_id ,
@@ -2562,5 +2713,5 @@ def handle_engagement_deny_submission_event(
25622713 client .chat_update (
25632714 blocks = blocks ,
25642715 channel = case .conversation .channel_id ,
2565- ts = signal_instance . engagement_thread_ts ,
2716+ ts = thread_ts ,
25662717 )
0 commit comments