1use std::collections::HashMap;
2
3use uuid::Uuid;
4
5use crate::types::{ChimeConfig, SlackConfig, TeamsConfig};
6
7#[derive(Debug, Default)]
8pub struct ChatbotState {
9 pub slack_configs: HashMap<String, SlackConfig>,
10 pub chime_configs: HashMap<String, ChimeConfig>,
11 pub teams_configs: HashMap<String, TeamsConfig>,
12}
13
14#[derive(Debug, thiserror::Error)]
15pub enum ChatbotError {
16 #[error("Configuration not found: {0}")]
17 ConfigurationNotFound(String),
18 #[error("Resource not found: {0}")]
19 ResourceNotFound(String),
20}
21
22impl ChatbotState {
23 #[allow(clippy::too_many_arguments)]
24 pub fn create_slack_channel_configuration(
25 &mut self,
26 account_id: &str,
27 region: &str,
28 configuration_name: &str,
29 slack_team_id: &str,
30 slack_channel_id: &str,
31 slack_channel_name: Option<String>,
32 iam_role_arn: &str,
33 sns_topic_arns: Vec<String>,
34 logging_level: Option<String>,
35 guardrail_policy_arns: Vec<String>,
36 user_authorization_required: Option<bool>,
37 tags: HashMap<String, String>,
38 ) -> Result<SlackConfig, ChatbotError> {
39 let arn = format!(
40 "arn:aws:chatbot:{}:{}:chat-configuration/slack-channel/{}",
41 region, account_id, configuration_name
42 );
43 let config = SlackConfig {
44 arn: arn.clone(),
45 configuration_name: configuration_name.to_string(),
46 slack_team_id: slack_team_id.to_string(),
47 slack_channel_id: slack_channel_id.to_string(),
48 slack_channel_name,
49 iam_role_arn: iam_role_arn.to_string(),
50 sns_topic_arns,
51 logging_level,
52 guardrail_policy_arns,
53 user_authorization_required,
54 tags,
55 };
56 self.slack_configs.insert(arn, config.clone());
57 Ok(config)
58 }
59
60 pub fn describe_slack_channel_configurations(
61 &self,
62 filter_arn: Option<&str>,
63 ) -> Vec<&SlackConfig> {
64 if let Some(arn) = filter_arn {
65 self.slack_configs.get(arn).into_iter().collect()
66 } else {
67 self.slack_configs.values().collect()
68 }
69 }
70
71 #[allow(clippy::too_many_arguments)]
72 pub fn update_slack_channel_configuration(
73 &mut self,
74 chat_configuration_arn: &str,
75 slack_channel_id: &str,
76 slack_channel_name: Option<String>,
77 iam_role_arn: Option<String>,
78 sns_topic_arns: Option<Vec<String>>,
79 logging_level: Option<String>,
80 guardrail_policy_arns: Option<Vec<String>>,
81 user_authorization_required: Option<bool>,
82 ) -> Result<SlackConfig, ChatbotError> {
83 let config = self
84 .slack_configs
85 .get_mut(chat_configuration_arn)
86 .ok_or_else(|| {
87 ChatbotError::ConfigurationNotFound(chat_configuration_arn.to_string())
88 })?;
89 config.slack_channel_id = slack_channel_id.to_string();
90 if let Some(name) = slack_channel_name {
91 config.slack_channel_name = Some(name);
92 }
93 if let Some(iam) = iam_role_arn {
94 config.iam_role_arn = iam;
95 }
96 if let Some(arns) = sns_topic_arns {
97 config.sns_topic_arns = arns;
98 }
99 if let Some(level) = logging_level {
100 config.logging_level = Some(level);
101 }
102 if let Some(arns) = guardrail_policy_arns {
103 config.guardrail_policy_arns = arns;
104 }
105 if let Some(auth) = user_authorization_required {
106 config.user_authorization_required = Some(auth);
107 }
108 Ok(config.clone())
109 }
110
111 pub fn delete_slack_channel_configuration(
112 &mut self,
113 chat_configuration_arn: &str,
114 ) -> Result<(), ChatbotError> {
115 if self.slack_configs.remove(chat_configuration_arn).is_none() {
116 return Err(ChatbotError::ConfigurationNotFound(
117 chat_configuration_arn.to_string(),
118 ));
119 }
120 Ok(())
121 }
122
123 #[allow(clippy::too_many_arguments)]
124 pub fn create_chime_webhook_configuration(
125 &mut self,
126 account_id: &str,
127 region: &str,
128 configuration_name: &str,
129 webhook_url: &str,
130 webhook_description: &str,
131 iam_role_arn: &str,
132 sns_topic_arns: Vec<String>,
133 logging_level: Option<String>,
134 tags: HashMap<String, String>,
135 ) -> Result<ChimeConfig, ChatbotError> {
136 let id = Uuid::new_v4().to_string();
137 let arn = format!(
138 "arn:aws:chatbot:{}:{}:chat-configuration/chime-webhook/{}",
139 region, account_id, id
140 );
141 let config = ChimeConfig {
142 arn: arn.clone(),
143 configuration_name: configuration_name.to_string(),
144 webhook_url: webhook_url.to_string(),
145 webhook_description: webhook_description.to_string(),
146 iam_role_arn: iam_role_arn.to_string(),
147 sns_topic_arns,
148 logging_level,
149 tags,
150 };
151 self.chime_configs.insert(arn, config.clone());
152 Ok(config)
153 }
154
155 pub fn describe_chime_webhook_configurations(
156 &self,
157 filter_arn: Option<&str>,
158 ) -> Vec<&ChimeConfig> {
159 if let Some(arn) = filter_arn {
160 self.chime_configs.get(arn).into_iter().collect()
161 } else {
162 self.chime_configs.values().collect()
163 }
164 }
165
166 pub fn delete_chime_webhook_configuration(
167 &mut self,
168 chat_configuration_arn: &str,
169 ) -> Result<(), ChatbotError> {
170 if self.chime_configs.remove(chat_configuration_arn).is_none() {
171 return Err(ChatbotError::ConfigurationNotFound(
172 chat_configuration_arn.to_string(),
173 ));
174 }
175 Ok(())
176 }
177
178 #[allow(clippy::too_many_arguments)]
179 pub fn create_microsoft_teams_channel_configuration(
180 &mut self,
181 account_id: &str,
182 region: &str,
183 configuration_name: &str,
184 team_id: &str,
185 team_name: Option<String>,
186 tenant_id: &str,
187 channel_id: &str,
188 channel_name: Option<String>,
189 iam_role_arn: &str,
190 sns_topic_arns: Vec<String>,
191 logging_level: Option<String>,
192 guardrail_policy_arns: Vec<String>,
193 user_authorization_required: Option<bool>,
194 tags: HashMap<String, String>,
195 ) -> Result<TeamsConfig, ChatbotError> {
196 let arn = format!(
197 "arn:aws:chatbot:{}:{}:chat-configuration/microsoft-teams-channel/{}",
198 region, account_id, configuration_name
199 );
200 let config = TeamsConfig {
201 arn: arn.clone(),
202 configuration_name: configuration_name.to_string(),
203 team_id: team_id.to_string(),
204 team_name,
205 tenant_id: tenant_id.to_string(),
206 channel_id: channel_id.to_string(),
207 channel_name,
208 iam_role_arn: iam_role_arn.to_string(),
209 sns_topic_arns,
210 logging_level,
211 guardrail_policy_arns,
212 user_authorization_required,
213 tags,
214 };
215 self.teams_configs.insert(arn, config.clone());
216 Ok(config)
217 }
218
219 pub fn list_microsoft_teams_channel_configurations(
220 &self,
221 filter_arn: Option<&str>,
222 ) -> Vec<&TeamsConfig> {
223 if let Some(arn) = filter_arn {
224 self.teams_configs.get(arn).into_iter().collect()
225 } else {
226 self.teams_configs.values().collect()
227 }
228 }
229
230 pub fn delete_microsoft_teams_channel_configuration(
231 &mut self,
232 chat_configuration_arn: &str,
233 ) -> Result<(), ChatbotError> {
234 if self.teams_configs.remove(chat_configuration_arn).is_none() {
235 return Err(ChatbotError::ConfigurationNotFound(
236 chat_configuration_arn.to_string(),
237 ));
238 }
239 Ok(())
240 }
241
242 pub fn get_microsoft_teams_channel_configuration(
245 &self,
246 chat_configuration_arn: &str,
247 ) -> Result<&TeamsConfig, ChatbotError> {
248 self.teams_configs
249 .get(chat_configuration_arn)
250 .ok_or_else(|| ChatbotError::ConfigurationNotFound(chat_configuration_arn.to_string()))
251 }
252
253 #[allow(clippy::too_many_arguments)]
256 pub fn update_microsoft_teams_channel_configuration(
257 &mut self,
258 chat_configuration_arn: &str,
259 channel_id: &str,
260 channel_name: Option<String>,
261 iam_role_arn: Option<String>,
262 sns_topic_arns: Option<Vec<String>>,
263 logging_level: Option<String>,
264 guardrail_policy_arns: Option<Vec<String>>,
265 user_authorization_required: Option<bool>,
266 ) -> Result<TeamsConfig, ChatbotError> {
267 let config = self
268 .teams_configs
269 .get_mut(chat_configuration_arn)
270 .ok_or_else(|| {
271 ChatbotError::ConfigurationNotFound(chat_configuration_arn.to_string())
272 })?;
273 config.channel_id = channel_id.to_string();
274 if let Some(name) = channel_name {
275 config.channel_name = Some(name);
276 }
277 if let Some(iam) = iam_role_arn {
278 config.iam_role_arn = iam;
279 }
280 if let Some(arns) = sns_topic_arns {
281 config.sns_topic_arns = arns;
282 }
283 if let Some(level) = logging_level {
284 config.logging_level = Some(level);
285 }
286 if let Some(arns) = guardrail_policy_arns {
287 config.guardrail_policy_arns = arns;
288 }
289 if let Some(auth) = user_authorization_required {
290 config.user_authorization_required = Some(auth);
291 }
292 Ok(config.clone())
293 }
294
295 pub fn list_tags_for_resource(
298 &self,
299 resource_arn: &str,
300 ) -> Result<HashMap<String, String>, ChatbotError> {
301 if let Some(config) = self.slack_configs.get(resource_arn) {
302 return Ok(config.tags.clone());
303 }
304 if let Some(config) = self.chime_configs.get(resource_arn) {
305 return Ok(config.tags.clone());
306 }
307 if let Some(config) = self.teams_configs.get(resource_arn) {
308 return Ok(config.tags.clone());
309 }
310 Err(ChatbotError::ResourceNotFound(resource_arn.to_string()))
311 }
312
313 pub fn tag_resource(
315 &mut self,
316 resource_arn: &str,
317 tags: HashMap<String, String>,
318 ) -> Result<(), ChatbotError> {
319 if let Some(config) = self.slack_configs.get_mut(resource_arn) {
320 config.tags.extend(tags);
321 return Ok(());
322 }
323 if let Some(config) = self.chime_configs.get_mut(resource_arn) {
324 config.tags.extend(tags);
325 return Ok(());
326 }
327 if let Some(config) = self.teams_configs.get_mut(resource_arn) {
328 config.tags.extend(tags);
329 return Ok(());
330 }
331 Err(ChatbotError::ResourceNotFound(resource_arn.to_string()))
332 }
333
334 pub fn untag_resource(
336 &mut self,
337 resource_arn: &str,
338 tag_keys: &[String],
339 ) -> Result<(), ChatbotError> {
340 if let Some(config) = self.slack_configs.get_mut(resource_arn) {
341 for key in tag_keys {
342 config.tags.remove(key);
343 }
344 return Ok(());
345 }
346 if let Some(config) = self.chime_configs.get_mut(resource_arn) {
347 for key in tag_keys {
348 config.tags.remove(key);
349 }
350 return Ok(());
351 }
352 if let Some(config) = self.teams_configs.get_mut(resource_arn) {
353 for key in tag_keys {
354 config.tags.remove(key);
355 }
356 return Ok(());
357 }
358 Err(ChatbotError::ResourceNotFound(resource_arn.to_string()))
359 }
360}