stat_summoner/module/askingforflex/interaction_flex_buttons.rs
1use crate::models::data::EmojiId;
2use crate::models::error::Error;
3use crate::utils::get_emoji;
4use mongodb::Collection;
5use poise::serenity_prelude::CacheHttp;
6use poise::serenity_prelude::{ComponentInteraction, CreateEmbed};
7use std::str::FromStr;
8
9/// Handles flex interactions with buttons in Discord messages.
10///
11/// This function processes button clicks in Discord related to the flex feature, specifically those with a custom_id
12/// starting with `flex_user:`. It identifies the user and the selected role, updates the embed message to reflect the user's choice,
13/// and manages role assignments based on the presence of existing users.
14///
15/// # Parameters:
16/// - ctx: The context of the interaction, providing access to the bot and its utilities.
17/// - message_component_interaction: The interaction object representing the button click event.
18/// - ctx_data: The application's shared data, containing the MongoDB client and other configuration details.
19///
20/// # Returns:
21/// - Result<(), Error>: Returns `Ok(())` if the interaction is processed successfully; otherwise, returns an `Error`.
22///
23/// # ⚠️ Notes:
24/// - The function checks if the `custom_id` starts with `flex_user:` to identify flex actions.
25/// - The `custom_id` must contain the role as a string after the prefix to parse the selected role.
26/// - Updates the Discord embed fields based on user selections and ensures only one user is assigned per role.
27/// - Handles setting and resetting user mentions in the embed fields dynamically.
28///
29/// # Example:
30///
31/// ```rust
32/// handle_interaction_button_flex(ctx, message_component_interaction, ctx_data).await?;
33/// ```
34///
35/// When a user clicks a "Flex" button for a specific role, the following actions occur:
36/// 1. The selected role is parsed from the `custom_id`.
37/// 2. The corresponding embed field is updated with the user's mention if it was previously empty.
38/// 3. If the user was already set in another role, that field is reset to `TBD`.
39/// 4. If the user is already in the selected role, the field is reset to `TBD`.
40/// 5. The modified embed is then updated in the original Discord message.
41///
42/// # Errors:
43/// - If the `custom_id` is not formatted correctly or the role is unrecognized, the function exits silently.
44/// - If any database operation with MongoDB fails, an error is returned.
45/// - If the message cannot be edited on Discord, an error is returned.
46///
47/// # See Also:
48/// - `get_emoji`: Retrieves emojis from the MongoDB collection for use in embed fields.
49/// - `Role`: Enum representing the different roles available in the flex feature.
50///
51/// # Related Structures:
52/// - `EmojiId`: Represents the structure for storing emoji identifiers in the database.
53/// - `Role`: Enum defining Top, Jungle, Mid, ADC, and Support roles.
54///
55/// # Dependencies:
56/// - Relies on MongoDB for storing and retrieving emoji data.
57/// - Uses `poise::serenity_prelude` for interacting with Discord messages and embeds.
58/// - Parses roles from button `custom_id` strings using `FromStr` trait.
59///
60/// ```
61pub async fn handle_interaction_button_flex(
62 ctx: poise::serenity_prelude::Context,
63 message_component_interaction: ComponentInteraction,
64 ctx_data: &crate::models::data::Data,
65) -> Result<(), Error> {
66 let custom_id = &message_component_interaction.data.custom_id;
67 let channel_id = message_component_interaction.message.channel_id;
68 let message_id = message_component_interaction.message.id;
69 let embed = message_component_interaction.message.embeds.get(0);
70 let user_mention = format!("<@{}>", message_component_interaction.user.id);
71 let mongo_client = ctx_data.mongo_client.clone();
72 let collection = mongo_client
73 .database("stat-summoner")
74 .collection::<EmojiId>("emojis_id");
75
76 if let Some(data) = custom_id.strip_prefix("flex_user:") {
77 if let Ok(role) = Role::from_str(data) {
78 if let Some(embed) = embed {
79 let mut new_embed = embed.clone();
80 let mut user_already_set = false;
81 for field in &new_embed.fields {
82 if field.value == user_mention {
83 user_already_set = true;
84 break;
85 }
86 }
87
88 for field in &mut new_embed.fields {
89 if field.name == role.field_name(&collection).await? {
90 if field.value == user_mention {
91 field.value = "TBD".to_string();
92 } else if field.value == "TBD" {
93 field.value = user_mention.clone();
94 }
95 } else if user_already_set && field.value == user_mention {
96 // If the user is already set in another field, set that field to "TBD"
97 field.value = "TBD".to_string();
98 }
99 }
100
101 let c_embed = CreateEmbed::from(new_embed);
102 channel_id
103 .edit_message(
104 &ctx.http(),
105 message_id,
106 poise::serenity_prelude::EditMessage::default().embed(c_embed),
107 )
108 .await?;
109 return Ok(());
110 }
111 }
112 }
113 Ok(())
114}
115
116enum Role {
117 Top,
118 Jungle,
119 Mid,
120 ADC,
121 Support,
122}
123
124impl FromStr for Role {
125 type Err = ();
126
127 fn from_str(input: &str) -> Result<Role, Self::Err> {
128 match input {
129 "top" => Ok(Role::Top),
130 "jungle" => Ok(Role::Jungle),
131 "mid" => Ok(Role::Mid),
132 "adc" => Ok(Role::ADC),
133 "support" => Ok(Role::Support),
134 _ => Err(()),
135 }
136 }
137}
138
139impl Role {
140 async fn field_name(&self, collection_emojis: &Collection<EmojiId>) -> Result<String, Error> {
141 match self {
142 Role::Top => {
143 let emoji = get_emoji(collection_emojis.clone(), "position", "TOP").await?;
144 Ok(format!("{}:", emoji))
145 }
146 Role::Jungle => {
147 let emoji = get_emoji(collection_emojis.clone(), "position", "JUNGLE").await?;
148 Ok(format!("{}:", emoji))
149 }
150 Role::Mid => {
151 let emoji = get_emoji(collection_emojis.clone(), "position", "MIDDLE").await?;
152 Ok(format!("{}:", emoji))
153 }
154 Role::ADC => {
155 let emoji = get_emoji(collection_emojis.clone(), "position", "BOTTOM").await?;
156 Ok(format!("{}:", emoji))
157 }
158 Role::Support => {
159 let emoji = get_emoji(collection_emojis.clone(), "position", "SUPPORT").await?;
160 Ok(format!("{}:", emoji))
161 }
162 }
163 }
164}