sfr_server/handler/
slash_command.rs

1//! The trait representing the interface that acts as a slash command.
2
3use sfr_core as sc;
4use sfr_slack_api as ssa;
5use sfr_types as st;
6
7use crate::handler::oauth::{OauthHandler, OauthHandlerTrait};
8use crate::{ResponseError, SlashCommandResponse};
9use axum::async_trait;
10use sc::SlashCommandBody;
11use ssa::Client as SlackClient;
12
13/// The trait representing the interface that acts as a slash command.
14#[async_trait]
15pub trait SlashCommandHandlerTrait: Send + Sync {
16    /// Handles [`SlashCommandBody`].
17    async fn handle_slash_command(
18        &self,
19        client: &SlackClient,
20        body: SlashCommandBody,
21    ) -> Result<st::SlashCommandResponse, ResponseError>;
22}
23
24/// The new type to wrap [`SlashCommandHandlerTrait`].
25#[derive(Clone)]
26pub(crate) struct SlashCommandHandler<T>(T)
27where
28    T: SlashCommandHandlerTrait;
29
30impl<T> SlashCommandHandler<T>
31where
32    T: SlashCommandHandlerTrait,
33{
34    /// The constructor.
35    pub fn new(inner: T) -> Self {
36        Self(inner)
37    }
38
39    /// The wrapper function for a slash command.
40
41    pub async fn handle<OH>(
42        &self,
43        client: reqwest::Client,
44        oauth: &OauthHandler<OH>,
45        body: SlashCommandBody,
46    ) -> Result<impl axum::response::IntoResponse, ResponseError>
47    where
48        OH: OauthHandlerTrait,
49    {
50        tracing::info!("slash command: start to process");
51
52        let token = oauth.take_oauth_token_from_team_id(&body.team_id).await?;
53        let client = SlackClient::new(client, token);
54
55        let resp: SlashCommandResponse = self.0.handle_slash_command(&client, body).await?.into();
56        Ok(resp)
57    }
58}
59
60impl<T> std::ops::Deref for SlashCommandHandler<T>
61where
62    T: SlashCommandHandlerTrait,
63{
64    type Target = T;
65
66    fn deref(&self) -> &Self::Target {
67        &self.0
68    }
69}