forked from jmug/stoatchat
@@ -3,8 +3,8 @@ use std::{collections::HashMap, sync::Arc};
|
||||
use futures::lock::Mutex;
|
||||
|
||||
use crate::{
|
||||
Bot, Channel, ChannelCompositeKey, ChannelUnread, File, Invite, Member, MemberCompositeKey,
|
||||
Server, User, UserSettings, Webhook,
|
||||
Bot, Channel, ChannelCompositeKey, ChannelUnread, Emoji, File, Invite, Member,
|
||||
MemberCompositeKey, Server, User, UserSettings, Webhook,
|
||||
};
|
||||
|
||||
database_derived!(
|
||||
@@ -16,6 +16,7 @@ database_derived!(
|
||||
pub channel_invites: Arc<Mutex<HashMap<String, Invite>>>,
|
||||
pub channel_unreads: Arc<Mutex<HashMap<ChannelCompositeKey, ChannelUnread>>>,
|
||||
pub channel_webhooks: Arc<Mutex<HashMap<String, Webhook>>>,
|
||||
pub emojis: Arc<Mutex<HashMap<String, Emoji>>>,
|
||||
pub user_settings: Arc<Mutex<HashMap<String, UserSettings>>>,
|
||||
pub users: Arc<Mutex<HashMap<String, User>>>,
|
||||
pub server_members: Arc<Mutex<HashMap<MemberCompositeKey, Member>>>,
|
||||
@@ -24,7 +25,6 @@ database_derived!(
|
||||
pub server_bans: Arc<Mutex<HashMap<String, ()>>>,
|
||||
pub safety_reports: Arc<Mutex<HashMap<String, ()>>>,
|
||||
pub safety_snapshots: Arc<Mutex<HashMap<String, ()>>>,
|
||||
pub emoji: Arc<Mutex<HashMap<String, ()>>>,
|
||||
pub messages: Arc<Mutex<HashMap<String, ()>>>,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -2,7 +2,8 @@ use authifier::AuthifierEvent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use revolt_models::v0::{
|
||||
Channel, FieldsChannel, FieldsWebhook, PartialChannel, PartialWebhook, Webhook,
|
||||
Channel, Emoji, FieldsChannel, FieldsWebhook, PartialChannel, PartialWebhook, UserSettings,
|
||||
Webhook,
|
||||
};
|
||||
use revolt_result::Error;
|
||||
|
||||
@@ -158,12 +159,11 @@ pub enum EventV1 {
|
||||
user: User,
|
||||
// ! this field can be deprecated
|
||||
status: RelationshipStatus,
|
||||
},
|
||||
|
||||
},*/
|
||||
/// Settings updated remotely
|
||||
UserSettingsUpdate { id: String, update: UserSettings },
|
||||
|
||||
/// User has been platform banned or deleted their account
|
||||
/*/// User has been platform banned or deleted their account
|
||||
///
|
||||
/// Clients should remove the following associated data:
|
||||
/// - Messages
|
||||
@@ -172,15 +172,14 @@ pub enum EventV1 {
|
||||
/// - Server Memberships
|
||||
///
|
||||
/// User flags are specified to explain why a wipe is occurring though not all reasons will necessarily ever appear.
|
||||
UserPlatformWipe { user_id: String, flags: i32 },
|
||||
|
||||
UserPlatformWipe { user_id: String, flags: i32 }, */
|
||||
/// New emoji
|
||||
EmojiCreate(Emoji),
|
||||
|
||||
/// Delete emoji
|
||||
EmojiDelete { id: String },
|
||||
|
||||
/// New report
|
||||
/*/// New report
|
||||
ReportCreate(Report), */
|
||||
/// New channel
|
||||
ChannelCreate(Channel),
|
||||
|
||||
5
crates/core/database/src/models/emojis/mod.rs
Normal file
5
crates/core/database/src/models/emojis/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
mod model;
|
||||
mod ops;
|
||||
|
||||
pub use model::*;
|
||||
pub use ops::*;
|
||||
87
crates/core/database/src/models/emojis/model.rs
Normal file
87
crates/core/database/src/models/emojis/model.rs
Normal file
@@ -0,0 +1,87 @@
|
||||
use std::collections::HashSet;
|
||||
use std::str::FromStr;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use revolt_result::Result;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::events::client::EventV1;
|
||||
use crate::Database;
|
||||
|
||||
static PERMISSIBLE_EMOJIS: Lazy<HashSet<String>> = Lazy::new(|| {
|
||||
include_str!("unicode_emoji.txt")
|
||||
.split('\n')
|
||||
.map(|x| x.into())
|
||||
.collect()
|
||||
});
|
||||
|
||||
auto_derived!(
|
||||
/// Emoji
|
||||
pub struct Emoji {
|
||||
/// Unique Id
|
||||
#[serde(rename = "_id")]
|
||||
pub id: String,
|
||||
/// What owns this emoji
|
||||
pub parent: EmojiParent,
|
||||
/// Uploader user id
|
||||
pub creator_id: String,
|
||||
/// Emoji name
|
||||
pub name: String,
|
||||
/// Whether the emoji is animated
|
||||
#[serde(skip_serializing_if = "crate::if_false", default)]
|
||||
pub animated: bool,
|
||||
/// Whether the emoji is marked as nsfw
|
||||
#[serde(skip_serializing_if = "crate::if_false", default)]
|
||||
pub nsfw: bool,
|
||||
}
|
||||
|
||||
/// Parent Id of the emoji
|
||||
#[serde(tag = "type")]
|
||||
pub enum EmojiParent {
|
||||
Server { id: String },
|
||||
Detached,
|
||||
}
|
||||
);
|
||||
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
impl Emoji {
|
||||
/// Get parent id
|
||||
fn parent(&self) -> &str {
|
||||
match &self.parent {
|
||||
EmojiParent::Server { id } => id,
|
||||
EmojiParent::Detached => "",
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an emoji
|
||||
pub async fn create(&self, db: &Database) -> Result<()> {
|
||||
db.insert_emoji(self).await?;
|
||||
|
||||
EventV1::EmojiCreate(self.clone().into())
|
||||
.p(self.parent().to_string())
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Delete an emoji
|
||||
pub async fn delete(self, db: &Database) -> Result<()> {
|
||||
EventV1::EmojiDelete {
|
||||
id: self.id.to_string(),
|
||||
}
|
||||
.p(self.parent().to_string())
|
||||
.await;
|
||||
|
||||
db.detach_emoji(&self).await
|
||||
}
|
||||
|
||||
/// Check whether we can use a given emoji
|
||||
pub async fn can_use(db: &Database, emoji: &str) -> Result<bool> {
|
||||
if Ulid::from_str(emoji).is_ok() {
|
||||
db.fetch_emoji(emoji).await?;
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(PERMISSIBLE_EMOJIS.contains(emoji))
|
||||
}
|
||||
}
|
||||
}
|
||||
24
crates/core/database/src/models/emojis/ops.rs
Normal file
24
crates/core/database/src/models/emojis/ops.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use revolt_result::Result;
|
||||
|
||||
use crate::Emoji;
|
||||
|
||||
mod mongodb;
|
||||
mod reference;
|
||||
|
||||
#[async_trait]
|
||||
pub trait AbstractEmojis: Sync + Send {
|
||||
/// Insert emoji into database.
|
||||
async fn insert_emoji(&self, emoji: &Emoji) -> Result<()>;
|
||||
|
||||
/// Fetch an emoji by its id
|
||||
async fn fetch_emoji(&self, id: &str) -> Result<Emoji>;
|
||||
|
||||
/// Fetch emoji by their parent id
|
||||
async fn fetch_emoji_by_parent_id(&self, parent_id: &str) -> Result<Vec<Emoji>>;
|
||||
|
||||
/// Fetch emoji by their parent ids
|
||||
async fn fetch_emoji_by_parent_ids(&self, parent_ids: &[String]) -> Result<Vec<Emoji>>;
|
||||
|
||||
/// Detach an emoji by its id
|
||||
async fn detach_emoji(&self, emoji: &Emoji) -> Result<()>;
|
||||
}
|
||||
70
crates/core/database/src/models/emojis/ops/mongodb.rs
Normal file
70
crates/core/database/src/models/emojis/ops/mongodb.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
use bson::Document;
|
||||
use revolt_result::Result;
|
||||
|
||||
use crate::Emoji;
|
||||
use crate::MongoDb;
|
||||
|
||||
use super::AbstractEmojis;
|
||||
|
||||
static COL: &str = "emojis";
|
||||
|
||||
#[async_trait]
|
||||
impl AbstractEmojis for MongoDb {
|
||||
/// Insert emoji into database.
|
||||
async fn insert_emoji(&self, emoji: &Emoji) -> Result<()> {
|
||||
query!(self, insert_one, COL, &emoji).map(|_| ())
|
||||
}
|
||||
|
||||
/// Fetch an emoji by its id
|
||||
async fn fetch_emoji(&self, id: &str) -> Result<Emoji> {
|
||||
query!(self, find_one_by_id, COL, id)?.ok_or_else(|| create_error!(NotFound))
|
||||
}
|
||||
|
||||
/// Fetch emoji by their parent id
|
||||
async fn fetch_emoji_by_parent_id(&self, parent_id: &str) -> Result<Vec<Emoji>> {
|
||||
query!(
|
||||
self,
|
||||
find_one,
|
||||
COL,
|
||||
doc! {
|
||||
"parent.id": parent_id
|
||||
}
|
||||
)?
|
||||
.ok_or_else(|| create_error!(NotFound))
|
||||
}
|
||||
|
||||
/// Fetch emoji by their parent ids
|
||||
async fn fetch_emoji_by_parent_ids(&self, parent_ids: &[String]) -> Result<Vec<Emoji>> {
|
||||
query!(
|
||||
self,
|
||||
find,
|
||||
COL,
|
||||
doc! {
|
||||
"parent.id": {
|
||||
"$in": parent_ids
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Detach an emoji by its id
|
||||
async fn detach_emoji(&self, emoji: &Emoji) -> Result<()> {
|
||||
self.col::<Document>(COL)
|
||||
.update_one(
|
||||
doc! {
|
||||
"_id": &emoji.id
|
||||
},
|
||||
doc! {
|
||||
"$set": {
|
||||
"parent": {
|
||||
"type": "Detached"
|
||||
}
|
||||
}
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|_| ())
|
||||
.map_err(|_| create_database_error!("update_one", COL))
|
||||
}
|
||||
}
|
||||
67
crates/core/database/src/models/emojis/ops/reference.rs
Normal file
67
crates/core/database/src/models/emojis/ops/reference.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
use revolt_result::Result;
|
||||
|
||||
use crate::Emoji;
|
||||
use crate::EmojiParent;
|
||||
use crate::ReferenceDb;
|
||||
|
||||
use super::AbstractEmojis;
|
||||
|
||||
#[async_trait]
|
||||
impl AbstractEmojis for ReferenceDb {
|
||||
/// Insert emoji into database.
|
||||
async fn insert_emoji(&self, emoji: &Emoji) -> Result<()> {
|
||||
let mut emojis = self.emojis.lock().await;
|
||||
if emojis.contains_key(&emoji.id) {
|
||||
Err(create_database_error!("insert", "emoji"))
|
||||
} else {
|
||||
emojis.insert(emoji.id.to_string(), emoji.clone());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch an emoji by its id
|
||||
async fn fetch_emoji(&self, id: &str) -> Result<Emoji> {
|
||||
let emojis = self.emojis.lock().await;
|
||||
emojis
|
||||
.get(id)
|
||||
.cloned()
|
||||
.ok_or_else(|| create_error!(NotFound))
|
||||
}
|
||||
|
||||
/// Fetch emoji by their parent id
|
||||
async fn fetch_emoji_by_parent_id(&self, parent_id: &str) -> Result<Vec<Emoji>> {
|
||||
let emojis = self.emojis.lock().await;
|
||||
Ok(emojis
|
||||
.values()
|
||||
.filter(|emoji| match &emoji.parent {
|
||||
EmojiParent::Server { id } => id == parent_id,
|
||||
_ => false,
|
||||
})
|
||||
.cloned()
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// Fetch emoji by their parent ids
|
||||
async fn fetch_emoji_by_parent_ids(&self, parent_ids: &[String]) -> Result<Vec<Emoji>> {
|
||||
let emojis = self.emojis.lock().await;
|
||||
Ok(emojis
|
||||
.values()
|
||||
.filter(|emoji| match &emoji.parent {
|
||||
EmojiParent::Server { id } => parent_ids.contains(id),
|
||||
_ => false,
|
||||
})
|
||||
.cloned()
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// Detach an emoji by its id
|
||||
async fn detach_emoji(&self, emoji: &Emoji) -> Result<()> {
|
||||
let mut emojis = self.emojis.lock().await;
|
||||
if let Some(bot) = emojis.get_mut(&emoji.id) {
|
||||
bot.parent = EmojiParent::Detached;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(create_error!(NotFound))
|
||||
}
|
||||
}
|
||||
}
|
||||
1850
crates/core/database/src/models/emojis/unicode_emoji.txt
Normal file
1850
crates/core/database/src/models/emojis/unicode_emoji.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@ mod channel_invites;
|
||||
mod channel_unreads;
|
||||
mod channel_webhooks;
|
||||
mod channels;
|
||||
mod emojis;
|
||||
mod files;
|
||||
mod ratelimit_events;
|
||||
mod server_members;
|
||||
@@ -17,6 +18,7 @@ pub use channel_invites::*;
|
||||
pub use channel_unreads::*;
|
||||
pub use channel_webhooks::*;
|
||||
pub use channels::*;
|
||||
pub use emojis::*;
|
||||
pub use files::*;
|
||||
pub use ratelimit_events::*;
|
||||
pub use server_members::*;
|
||||
@@ -35,6 +37,7 @@ pub trait AbstractDatabase:
|
||||
+ channel_invites::AbstractChannelInvites
|
||||
+ channel_unreads::AbstractChannelUnreads
|
||||
+ channel_webhooks::AbstractWebhooks
|
||||
+ emojis::AbstractEmojis
|
||||
+ files::AbstractAttachments
|
||||
+ ratelimit_events::AbstractRatelimitEvents
|
||||
+ server_members::AbstractServerMembers
|
||||
|
||||
@@ -235,6 +235,28 @@ impl From<crate::FieldsChannel> for FieldsChannel {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::Emoji> for Emoji {
|
||||
fn from(value: crate::Emoji) -> Self {
|
||||
Emoji {
|
||||
id: value.id,
|
||||
parent: value.parent.into(),
|
||||
creator_id: value.creator_id,
|
||||
name: value.name,
|
||||
animated: value.animated,
|
||||
nsfw: value.nsfw,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::EmojiParent> for EmojiParent {
|
||||
fn from(value: crate::EmojiParent) -> Self {
|
||||
match value {
|
||||
crate::EmojiParent::Detached => EmojiParent::Detached,
|
||||
crate::EmojiParent::Server { id } => EmojiParent::Server { id },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::File> for File {
|
||||
fn from(value: crate::File) -> Self {
|
||||
File {
|
||||
|
||||
Reference in New Issue
Block a user