revolt_database/models/emojis/
model.rs1use std::collections::HashSet;
2use std::str::FromStr;
3
4use once_cell::sync::Lazy;
5use revolt_models::v0;
6use revolt_result::Result;
7use ulid::Ulid;
8
9use crate::events::client::EventV1;
10use crate::Database;
11
12static PERMISSIBLE_EMOJIS: Lazy<HashSet<String>> = Lazy::new(|| {
13 include_str!("unicode_emoji.txt")
14 .split('\n')
15 .map(|x| x.replace('\u{FE0F}', ""))
16 .collect()
17});
18
19auto_derived_partial!(
20 pub struct Emoji {
22 #[serde(rename = "_id")]
24 pub id: String,
25 pub parent: EmojiParent,
27 pub creator_id: String,
29 pub name: String,
31 #[serde(skip_serializing_if = "crate::if_false", default)]
33 pub animated: bool,
34 #[serde(skip_serializing_if = "crate::if_false", default)]
36 pub nsfw: bool,
37 },
38 "PartialEmoji"
39);
40
41auto_derived!(
42 #[serde(tag = "type")]
44 pub enum EmojiParent {
45 Server { id: String },
46 Detached,
47 }
48);
49
50#[allow(clippy::disallowed_methods)]
51impl Emoji {
52 fn parent(&self) -> &str {
54 match &self.parent {
55 EmojiParent::Server { id } => id,
56 EmojiParent::Detached => "",
57 }
58 }
59
60 pub async fn create(&self, db: &Database) -> Result<()> {
62 db.insert_emoji(self).await?;
63
64 EventV1::EmojiCreate(self.clone().into())
65 .p(self.parent().to_string())
66 .await;
67
68 Ok(())
69 }
70
71 pub async fn delete(&self, db: &Database) -> Result<()> {
73 EventV1::EmojiDelete {
74 id: self.id.to_string(),
75 }
76 .p(self.parent().to_string())
77 .await;
78
79 db.detach_emoji(self).await
80 }
81
82 pub async fn update(&mut self, db: &Database, partial: PartialEmoji) -> Result<()> {
84 if let Some(name) = partial.name.clone() {
85 self.name = name;
86 }
87
88 db.update_emoji(&self.id, &partial).await?;
89
90 EventV1::EmojiUpdate {
91 id: self.id.clone(),
92 data: v0::PartialEmoji {
93 name: partial.name.clone(),
94 },
95 }
96 .p(self.parent().to_string())
97 .await;
98
99 Ok(())
100 }
101
102 pub async fn can_use(db: &Database, emoji: &str) -> Result<bool> {
104 if Ulid::from_str(emoji).is_ok() {
105 db.fetch_emoji(emoji).await?;
106 Ok(true)
107 } else {
108 let sanitized_emoji = emoji.replace('\u{FE0F}', "");
109 Ok(PERMISSIBLE_EMOJIS.contains(&sanitized_emoji))
110 }
111 }
112
113 pub fn generate_diff(&self, partial: &PartialEmoji) -> PartialEmoji {
115 let mut before = PartialEmoji::default();
116
117 generate_diff!(
118 self, before, partial, remove,
119 (
120 name,
121 )
122 );
123
124 before
125 }
126}