Skip to main content

revolt_database/models/emojis/
model.rs

1use 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.into())
16        .collect()
17});
18
19auto_derived!(
20    /// Emoji
21    pub struct Emoji {
22        /// Unique Id
23        #[serde(rename = "_id")]
24        pub id: String,
25        /// What owns this emoji
26        pub parent: EmojiParent,
27        /// Uploader user id
28        pub creator_id: String,
29        /// Emoji name
30        pub name: String,
31        /// Whether the emoji is animated
32        #[serde(skip_serializing_if = "crate::if_false", default)]
33        pub animated: bool,
34        /// Whether the emoji is marked as nsfw
35        #[serde(skip_serializing_if = "crate::if_false", default)]
36        pub nsfw: bool,
37    }
38
39    /// Parent Id of the emoji
40    #[serde(tag = "type")]
41    pub enum EmojiParent {
42        Server { id: String },
43        Detached,
44    }
45
46    /// Partial representation of an emoji
47    pub struct PartialEmoji {
48        #[serde(skip_serializing_if = "Option::is_none")]
49        pub name: Option<String>,
50    }
51);
52
53#[allow(clippy::disallowed_methods)]
54impl Emoji {
55    /// Get parent id
56    fn parent(&self) -> &str {
57        match &self.parent {
58            EmojiParent::Server { id } => id,
59            EmojiParent::Detached => "",
60        }
61    }
62
63    /// Create an emoji
64    pub async fn create(&self, db: &Database) -> Result<()> {
65        db.insert_emoji(self).await?;
66
67        EventV1::EmojiCreate(self.clone().into())
68            .p(self.parent().to_string())
69            .await;
70
71        Ok(())
72    }
73
74    /// Delete an emoji
75    pub async fn delete(self, db: &Database) -> Result<()> {
76        EventV1::EmojiDelete {
77            id: self.id.to_string(),
78        }
79        .p(self.parent().to_string())
80        .await;
81
82        db.detach_emoji(&self).await
83    }
84
85    /// Update an emoji
86    pub async fn update(&mut self, db: &Database, partial: PartialEmoji) -> Result<()> {
87        if let Some(name) = partial.name.clone() {
88            self.name = name;
89        }
90
91        db.update_emoji(&self.id, &partial).await?;
92
93        EventV1::EmojiUpdate {
94            id: self.id.clone(),
95            data: v0::PartialEmoji {
96                name: partial.name.clone(),
97            },
98        }
99        .p(self.parent().to_string())
100        .await;
101
102        Ok(())
103    }
104
105    /// Check whether we can use a given emoji
106    pub async fn can_use(db: &Database, emoji: &str) -> Result<bool> {
107        if Ulid::from_str(emoji).is_ok() {
108            db.fetch_emoji(emoji).await?;
109            Ok(true)
110        } else {
111            Ok(PERMISSIBLE_EMOJIS.contains(emoji))
112        }
113    }
114}