serenity_builder/
embed.rs1use serenity::all::{Colour, CreateEmbed};
2
3use crate::model::embed::SerenityEmbed;
4
5#[derive(thiserror::Error, Debug)]
7pub enum SerenityEmbedConvertError {
8 #[error("The description exceeds the maximum length of 4096 characters.")]
15 TooLongDescription,
16 #[error("The number of fields exceeds the maximum of 25.")]
23 TooManyFields,
24}
25
26impl SerenityEmbed {
27 pub fn convert(&self) -> Result<CreateEmbed, SerenityEmbedConvertError> {
63 let mut embed = serenity::builder::CreateEmbed::default();
64
65 if let Some(title) = &self.title {
66 embed = embed.title(title)
67 }
68
69 if let Some(description) = &self.description {
70 if description.len() > 4096 {
71 return Err(SerenityEmbedConvertError::TooLongDescription);
72 }
73
74 embed = embed.description(description);
75 }
76
77 if let Some(url) = &self.url {
78 embed = embed.url(url);
79 }
80
81 if let Some(timestamp) = &self.timestamp {
82 embed = embed.timestamp(timestamp);
83 }
84
85 if let Some(color) = &self.color {
86 embed = embed.color(Colour(*color));
87 }
88
89 if let Some(footer_text) = &self.footer_text {
90 let mut footer = serenity::builder::CreateEmbedFooter::new(footer_text);
91 if let Some(icon_url) = &self.footer_icon_url {
92 footer = footer.icon_url(icon_url);
93 }
94 embed = embed.footer(footer);
95 }
96
97 if let Some(image_url) = &self.image_url {
98 embed = embed.image(image_url);
99 }
100
101 if let Some(thumbnail_url) = &self.thumbnail_url {
102 embed = embed.thumbnail(thumbnail_url);
103 }
104
105 if let Some(author_name) = &self.author_name {
106 let mut author = serenity::builder::CreateEmbedAuthor::new(author_name);
107 if let Some(url) = &self.author_url {
108 author = author.url(url);
109 }
110 if let Some(icon_url) = &self.author_icon_url {
111 author = author.icon_url(icon_url);
112 }
113 embed = embed.author(author);
114 }
115
116 if let Some(fields) = &self.fields {
117 if fields.len() > 25 {
118 return Err(SerenityEmbedConvertError::TooManyFields);
119 }
120 let mapped = fields
122 .iter()
123 .map(|f| (f.name.clone(), f.value.clone(), f.inline));
124 embed = embed.fields(mapped)
125 }
126
127 Ok(embed)
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 use crate::model::embed::SerenityEmbedField;
135 use serenity::all::Timestamp;
136
137 static MOCK_TEXT: &str = "This is a test text.";
138 static MOCK_URL: &str = "https://example.com";
139 static MOCK_TIMESTAMP_STR: &str = "2024-01-01T00:00:00Z";
140 static MOCK_COLOR: u32 = 0xff0000;
141
142 #[test]
143 fn test_embed_conversion() {
144 let fields = vec![
145 SerenityEmbedField::builder()
146 .name(MOCK_TEXT)
147 .value(MOCK_TEXT)
148 .inline(true)
149 .build(),
150 SerenityEmbedField::builder()
151 .name(MOCK_TEXT)
152 .value(MOCK_TEXT)
153 .build(),
154 ];
155
156 let mock_embed = SerenityEmbed::builder()
158 .title(MOCK_TEXT)
159 .description(MOCK_TEXT)
160 .url(MOCK_URL)
161 .timestamp(Timestamp::parse(MOCK_TIMESTAMP_STR).unwrap())
162 .color(MOCK_COLOR)
163 .footer_text(MOCK_TEXT)
164 .footer_icon_url(MOCK_URL)
165 .image_url(MOCK_URL)
166 .thumbnail_url(MOCK_URL)
167 .author_name(MOCK_TEXT)
168 .author_url(MOCK_URL)
169 .author_icon_url(MOCK_URL)
170 .fields(fields)
171 .build();
172 let serenity_embed = CreateEmbed::default()
174 .title(MOCK_TEXT)
175 .url(MOCK_URL)
176 .description(MOCK_TEXT)
177 .timestamp(Timestamp::parse(MOCK_TIMESTAMP_STR).unwrap())
178 .color(Colour(MOCK_COLOR))
179 .footer(serenity::builder::CreateEmbedFooter::new(MOCK_TEXT).icon_url(MOCK_URL))
180 .image(MOCK_URL)
181 .thumbnail(MOCK_URL)
182 .author(
183 serenity::builder::CreateEmbedAuthor::new(MOCK_TEXT)
184 .url(MOCK_URL)
185 .icon_url(MOCK_URL),
186 )
187 .fields(vec![
188 (MOCK_TEXT.to_string(), MOCK_TEXT.to_string(), true),
189 (MOCK_TEXT.to_string(), MOCK_TEXT.to_string(), false),
190 ]);
191
192 let converted = mock_embed.convert();
193
194 assert!(converted.is_ok());
195 assert_eq!(converted.unwrap(), serenity_embed);
196 }
197}