slack_morphism/models/blocks/
view.rs1use crate::blocks::kit::SlackBlock;
2use crate::blocks::{SlackBlockId, SlackBlockPlainText, SlackBlockPlainTextOnly};
3use crate::SlackCallbackId;
4use crate::*;
5use rsb_derive::Builder;
6use serde::{Deserialize, Serialize};
7use serde_with::{serde_as, skip_serializing_none};
8use std::collections::HashMap;
9
10#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
11#[serde(tag = "type")]
12pub enum SlackView {
13 #[serde(rename = "home")]
14 Home(SlackHomeView),
15 #[serde(rename = "modal")]
16 Modal(SlackModalView),
17}
18
19#[serde_as]
20#[skip_serializing_none]
21#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
22pub struct SlackHomeView {
23 pub blocks: Vec<SlackBlock>,
24 #[serde(default)]
25 #[serde_as(as = "serde_with::NoneAsEmptyString")]
26 pub private_metadata: Option<String>,
27 #[serde(default)]
28 #[serde_as(as = "serde_with::NoneAsEmptyString")]
29 pub callback_id: Option<SlackCallbackId>,
30 #[serde(default)]
31 #[serde_as(as = "serde_with::NoneAsEmptyString")]
32 pub external_id: Option<String>,
33}
34
35#[serde_as]
36#[skip_serializing_none]
37#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
38pub struct SlackModalView {
39 pub title: SlackBlockPlainTextOnly,
40 pub blocks: Vec<SlackBlock>,
41 pub close: Option<SlackBlockPlainTextOnly>,
42 pub submit: Option<SlackBlockPlainTextOnly>,
43 #[serde(default)]
44 #[serde_as(as = "serde_with::NoneAsEmptyString")]
45 pub private_metadata: Option<String>,
46 #[serde(default)]
47 #[serde_as(as = "serde_with::NoneAsEmptyString")]
48 pub callback_id: Option<SlackCallbackId>,
49 pub clear_on_close: Option<bool>,
50 pub notify_on_close: Option<bool>,
51 pub hash: Option<String>,
52 #[serde(default)]
53 #[serde_as(as = "serde_with::NoneAsEmptyString")]
54 pub external_id: Option<String>,
55}
56
57#[skip_serializing_none]
58#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
59pub struct SlackStatefulView {
60 #[serde(flatten)]
61 pub state_params: SlackStatefulStateParams,
62 #[serde(flatten)]
63 pub view: SlackView,
64}
65
66#[skip_serializing_none]
67#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
68pub struct SlackStatefulStateParams {
69 pub id: SlackViewId,
70 pub team_id: SlackTeamId,
71 pub state: Option<SlackViewState>,
72 pub hash: String,
73 pub previous_view_id: Option<SlackViewId>,
74 pub root_view_id: Option<SlackViewId>,
75 pub app_id: Option<SlackAppId>,
76 pub bot_id: Option<SlackBotId>,
77}
78
79#[skip_serializing_none]
80#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
81pub struct SlackViewState {
82 pub values: HashMap<SlackBlockId, HashMap<SlackActionId, SlackViewStateValue>>,
83}
84
85#[skip_serializing_none]
86#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
87pub struct SlackViewStateValue {
88 #[serde(rename = "type")]
89 pub action_type: SlackActionType,
90 pub value: Option<String>,
91 pub selected_date: Option<String>,
92 pub selected_time: Option<String>,
93 pub selected_date_time: Option<SlackDateTime>,
94 pub selected_conversation: Option<SlackConversationId>,
95 pub selected_channel: Option<SlackChannelId>,
96 pub selected_user: Option<SlackUserId>,
97 pub selected_option: Option<SlackViewStateValueSelectedOption>,
98 pub selected_conversations: Option<Vec<SlackConversationId>>,
99 pub selected_users: Option<Vec<SlackUserId>>,
100 pub selected_options: Option<Vec<SlackViewStateValueSelectedOption>>,
101}
102
103pub type SlackActionState = SlackViewState;
104pub type SlackActionStateValue = SlackViewStateValue;
105
106#[skip_serializing_none]
107#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
108pub struct SlackViewStateValueSelectedOption {
109 pub text: SlackBlockPlainText,
110 pub value: String,
111}
112
113#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
114#[serde(tag = "response_action")]
115pub enum SlackViewSubmissionResponse {
116 #[serde(rename = "clear")]
117 Clear(SlackViewSubmissionClearResponse),
118 #[serde(rename = "update")]
119 Update(SlackViewSubmissionUpdateResponse),
120 #[serde(rename = "push")]
121 Push(SlackViewSubmissionPushResponse),
122 #[serde(rename = "errors")]
123 Errors(SlackViewSubmissionErrorsResponse),
124}
125
126#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
127pub struct SlackViewSubmissionClearResponse {}
128
129#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
130pub struct SlackViewSubmissionUpdateResponse {
131 pub view: SlackView,
132}
133
134#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
135pub struct SlackViewSubmissionPushResponse {
136 pub view: SlackView,
137}
138
139#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
140pub struct SlackViewSubmissionErrorsResponse {
141 pub errors: HashMap<String, String>,
142}
143
144#[cfg(test)]
145mod test {
146 use super::*;
147
148 #[test]
149 fn test_slack_view_submission_clear_response_serialization() {
150 let output = serde_json::to_string(&SlackViewSubmissionResponse::Clear(
151 SlackViewSubmissionClearResponse::new(),
152 ))
153 .unwrap();
154 assert_eq!(output, r#"{"response_action":"clear"}"#);
155 }
156
157 #[test]
158 fn test_slack_api_apps_manifest_create_request() {
159 let payload = include_str!("./fixtures/slack_home_view.json");
160 let model: SlackHomeView = serde_json::from_str(payload).unwrap();
161 assert!(model.private_metadata.is_none());
162 assert_eq!(
163 model.callback_id,
164 Some(SlackCallbackId::from("test-callback-id"))
165 );
166 }
167}