refactor: refactor interactions

This commit is contained in:
Suya1671 2025-06-21 13:22:22 +02:00
parent 561d07efe2
commit 9c0b51db2b
No known key found for this signature in database

View file

@ -4,12 +4,13 @@ use std::error::Error;
use std::sync::Arc;
use axum::Extension;
use error_stack::Report;
use member::{create_member, edit_member};
use slack_morphism::prelude::*;
use tracing::{debug, error};
use trigger::{create_trigger, edit_trigger};
use crate::fields;
use crate::BOT_TOKEN;
use crate::models::system::System;
use crate::models::{self, Trusted, user};
@ -34,69 +35,72 @@ async fn interaction_event(
) -> Result<(), Box<dyn Error + Send + Sync>> {
match event {
SlackInteractionEvent::ViewSubmission(slack_interaction_view_submission_event) => {
match slack_interaction_view_submission_event.view.view {
SlackView::Home(view) => {
debug!(?view, "Received home view");
Ok(())
}
SlackView::Modal(ref view) => {
debug!(?view, "Received modal view");
let user_id: user::Id<Trusted> =
slack_interaction_view_submission_event.user.id.into();
let states = states.read().await;
let user_state = states.get_user_state::<user::State>().unwrap();
fields!(user_id = %&user_id);
let Some(view_state) = slack_interaction_view_submission_event
.view
.state_params
.state
else {
error!("No state found in view submission");
return Ok(());
};
handle_modal_view(
client,
view_state,
user_state,
user_id,
view.external_id.as_deref(),
)
.await
}
}
handle_view_submission(slack_interaction_view_submission_event, client, states).await
}
SlackInteractionEvent::Shortcut(shortcut) => {
debug!(?shortcut, "Received shortcut event");
todo!()
}
event => {
debug!("Received interaction event: {:#?}", event);
debug!(?event, "Received interaction event",);
Ok(())
}
}
}
#[tracing::instrument(skip(client, view_state, user_state))]
async fn handle_view_submission(
view_submission: SlackInteractionViewSubmissionEvent,
client: Arc<SlackHyperClient>,
states: SlackClientEventsUserState,
) -> Result<(), Box<dyn Error + Send + Sync>> {
match view_submission.view.view {
SlackView::Home(view) => {
debug!(?view, "Received home view");
Ok(())
}
SlackView::Modal(view) => {
debug!(?view, "Received modal view");
let user_id: user::Id<Trusted> = view_submission.user.id.into();
let Some(view_state) = view_submission.view.state_params.state else {
error!("No state found in modal view submission");
return Ok(());
};
handle_modal_view(client, view, view_state, states, user_id).await;
Ok(())
}
}
}
#[tracing::instrument(skip(client, view, states))]
async fn handle_modal_view(
client: Arc<SlackHyperClient>,
view: SlackModalView,
view_state: SlackViewState,
user_state: &user::State,
states: SlackClientEventsUserState,
user_id: user::Id<Trusted>,
external_id: Option<&str>,
) -> Result<(), Box<dyn Error + Send + Sync>> {
) {
let states = states.read().await;
let user_state = states.get_user_state::<user::State>().unwrap();
let external_id = view.external_id.as_deref();
match external_id {
None => {
error!(
"No external id found in modal view. To the person that created the modal: How do you expect the bot to figure out what to do?"
);
Ok(())
}
Some("create_member") => {
debug!("Received create member modal view");
create_member(view_state, &client, user_state, user_id).await?;
Ok(())
if let Err(error) =
create_member(view_state, &client, user_state, user_id.clone()).await
{
handle_user_error(error, user_id.into(), client).await;
}
}
Some(id) if id.starts_with("edit_member_") => {
debug!("Received edit member modal view");
@ -111,22 +115,31 @@ async fn handle_modal_view(
id,
"Failed to parse member id from external id. Bailing in case this was a malicious call",
);
return Ok(());
return;
};
let Some(trusted_member_id) =
member_id.validate_by_user(&user_id, &user_state.db).await?
// TO-DO: better handling of Err case
let Ok(Some(trusted_member_id)) =
member_id.validate_by_user(&user_id, &user_state.db).await
else {
error!(
id,
"Failed to validate member id from external id. Bailing in case this was a malicious call",
);
return Ok(());
return;
};
edit_member(view_state, &client, user_state, user_id, trusted_member_id).await?;
Ok(())
if let Err(error) = edit_member(
view_state,
&client,
user_state,
user_id.clone(),
trusted_member_id,
)
.await
{
handle_user_error(error, user_id.into(), client).await;
}
}
Some(id) if id.starts_with("create_trigger_") => {
debug!("Creating trigger");
@ -138,18 +151,28 @@ async fn handle_modal_view(
.map(models::member::Id::new)
.expect("Failed to parse member id from external id");
let Some(trusted_member_id) =
member_id.validate_by_user(&user_id, &user_state.db).await?
// TO-DO: Better handling of Err case
let Ok(Some(trusted_member_id)) =
member_id.validate_by_user(&user_id, &user_state.db).await
else {
error!(
id,
"Failed to validate member id from external id. Bailing in case this was a malicious call",
);
return Ok(());
return;
};
create_trigger(view_state, &client, user_state, user_id, trusted_member_id).await?;
Ok(())
if let Err(error) = create_trigger(
view_state,
&client,
user_state,
user_id.clone(),
trusted_member_id,
)
.await
{
handle_user_error(error, user_id.into(), client).await;
};
}
Some(id) if id.starts_with("edit_trigger_") => {
debug!("Editing trigger");
@ -170,7 +193,7 @@ async fn handle_modal_view(
%user_id,
"Failed to fetch system id for user id. Bailing in case this was a malicious call"
);
return Ok(());
return;
};
let Ok(trusted_trigger_id) = trigger_id
@ -181,15 +204,50 @@ async fn handle_modal_view(
"Failed to validate member id from external id {}. Bailing in case this was a malicious call",
id
);
return Ok(());
return;
};
edit_trigger(view_state, &client, user_state, user_id, trusted_trigger_id).await?;
Ok(())
if let Err(error) = edit_trigger(
view_state,
&client,
user_state,
user_id.clone(),
trusted_trigger_id,
)
.await
{
handle_user_error(error, user_id.into(), client.clone()).await;
}
}
Some(id) => {
error!("receieved unknown external id: {id}");
Ok(())
}
}
}
pub async fn handle_user_error<E>(
error: Report<E>,
user: SlackUserId,
client: Arc<SlackHyperClient>,
) where
E: std::error::Error + Send + Sync + 'static,
{
error!(?error);
let session = client.open_session(&BOT_TOKEN);
let conversation = session
.conversations_open(&SlackApiConversationsOpenRequest::new().with_users(vec![user.clone()]))
.await
.expect("Expected to be able to open conversation")
.channel;
session
.chat_post_ephemeral(&SlackApiChatPostEphemeralRequest::new(
conversation.id,
user,
SlackMessageContent::new().with_text(format!("An error occured! {error}",)),
))
.await
.expect("Expected to be able to post ephemeral message");
}