@@ -3,8 +3,8 @@ use std::{collections::HashMap, sync::Arc};
|
|||||||
use futures::lock::Mutex;
|
use futures::lock::Mutex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Bot, Channel, ChannelCompositeKey, ChannelUnread, File, Invite, Member, MemberCompositeKey,
|
Bot, Channel, ChannelCompositeKey, ChannelUnread, Emoji, File, Invite, Member,
|
||||||
Server, User, UserSettings, Webhook,
|
MemberCompositeKey, Server, User, UserSettings, Webhook,
|
||||||
};
|
};
|
||||||
|
|
||||||
database_derived!(
|
database_derived!(
|
||||||
@@ -16,6 +16,7 @@ database_derived!(
|
|||||||
pub channel_invites: Arc<Mutex<HashMap<String, Invite>>>,
|
pub channel_invites: Arc<Mutex<HashMap<String, Invite>>>,
|
||||||
pub channel_unreads: Arc<Mutex<HashMap<ChannelCompositeKey, ChannelUnread>>>,
|
pub channel_unreads: Arc<Mutex<HashMap<ChannelCompositeKey, ChannelUnread>>>,
|
||||||
pub channel_webhooks: Arc<Mutex<HashMap<String, Webhook>>>,
|
pub channel_webhooks: Arc<Mutex<HashMap<String, Webhook>>>,
|
||||||
|
pub emojis: Arc<Mutex<HashMap<String, Emoji>>>,
|
||||||
pub user_settings: Arc<Mutex<HashMap<String, UserSettings>>>,
|
pub user_settings: Arc<Mutex<HashMap<String, UserSettings>>>,
|
||||||
pub users: Arc<Mutex<HashMap<String, User>>>,
|
pub users: Arc<Mutex<HashMap<String, User>>>,
|
||||||
pub server_members: Arc<Mutex<HashMap<MemberCompositeKey, Member>>>,
|
pub server_members: Arc<Mutex<HashMap<MemberCompositeKey, Member>>>,
|
||||||
@@ -24,7 +25,6 @@ database_derived!(
|
|||||||
pub server_bans: Arc<Mutex<HashMap<String, ()>>>,
|
pub server_bans: Arc<Mutex<HashMap<String, ()>>>,
|
||||||
pub safety_reports: Arc<Mutex<HashMap<String, ()>>>,
|
pub safety_reports: Arc<Mutex<HashMap<String, ()>>>,
|
||||||
pub safety_snapshots: Arc<Mutex<HashMap<String, ()>>>,
|
pub safety_snapshots: Arc<Mutex<HashMap<String, ()>>>,
|
||||||
pub emoji: Arc<Mutex<HashMap<String, ()>>>,
|
|
||||||
pub messages: Arc<Mutex<HashMap<String, ()>>>,
|
pub messages: Arc<Mutex<HashMap<String, ()>>>,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ use authifier::AuthifierEvent;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use revolt_models::v0::{
|
use revolt_models::v0::{
|
||||||
Channel, FieldsChannel, FieldsWebhook, PartialChannel, PartialWebhook, Webhook,
|
Channel, Emoji, FieldsChannel, FieldsWebhook, PartialChannel, PartialWebhook, UserSettings,
|
||||||
|
Webhook,
|
||||||
};
|
};
|
||||||
use revolt_result::Error;
|
use revolt_result::Error;
|
||||||
|
|
||||||
@@ -158,12 +159,11 @@ pub enum EventV1 {
|
|||||||
user: User,
|
user: User,
|
||||||
// ! this field can be deprecated
|
// ! this field can be deprecated
|
||||||
status: RelationshipStatus,
|
status: RelationshipStatus,
|
||||||
},
|
},*/
|
||||||
|
|
||||||
/// Settings updated remotely
|
/// Settings updated remotely
|
||||||
UserSettingsUpdate { id: String, update: UserSettings },
|
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:
|
/// Clients should remove the following associated data:
|
||||||
/// - Messages
|
/// - Messages
|
||||||
@@ -172,15 +172,14 @@ pub enum EventV1 {
|
|||||||
/// - Server Memberships
|
/// - Server Memberships
|
||||||
///
|
///
|
||||||
/// User flags are specified to explain why a wipe is occurring though not all reasons will necessarily ever appear.
|
/// 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
|
/// New emoji
|
||||||
EmojiCreate(Emoji),
|
EmojiCreate(Emoji),
|
||||||
|
|
||||||
/// Delete emoji
|
/// Delete emoji
|
||||||
EmojiDelete { id: String },
|
EmojiDelete { id: String },
|
||||||
|
|
||||||
/// New report
|
/*/// New report
|
||||||
ReportCreate(Report), */
|
ReportCreate(Report), */
|
||||||
/// New channel
|
/// New channel
|
||||||
ChannelCreate(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_unreads;
|
||||||
mod channel_webhooks;
|
mod channel_webhooks;
|
||||||
mod channels;
|
mod channels;
|
||||||
|
mod emojis;
|
||||||
mod files;
|
mod files;
|
||||||
mod ratelimit_events;
|
mod ratelimit_events;
|
||||||
mod server_members;
|
mod server_members;
|
||||||
@@ -17,6 +18,7 @@ pub use channel_invites::*;
|
|||||||
pub use channel_unreads::*;
|
pub use channel_unreads::*;
|
||||||
pub use channel_webhooks::*;
|
pub use channel_webhooks::*;
|
||||||
pub use channels::*;
|
pub use channels::*;
|
||||||
|
pub use emojis::*;
|
||||||
pub use files::*;
|
pub use files::*;
|
||||||
pub use ratelimit_events::*;
|
pub use ratelimit_events::*;
|
||||||
pub use server_members::*;
|
pub use server_members::*;
|
||||||
@@ -35,6 +37,7 @@ pub trait AbstractDatabase:
|
|||||||
+ channel_invites::AbstractChannelInvites
|
+ channel_invites::AbstractChannelInvites
|
||||||
+ channel_unreads::AbstractChannelUnreads
|
+ channel_unreads::AbstractChannelUnreads
|
||||||
+ channel_webhooks::AbstractWebhooks
|
+ channel_webhooks::AbstractWebhooks
|
||||||
|
+ emojis::AbstractEmojis
|
||||||
+ files::AbstractAttachments
|
+ files::AbstractAttachments
|
||||||
+ ratelimit_events::AbstractRatelimitEvents
|
+ ratelimit_events::AbstractRatelimitEvents
|
||||||
+ server_members::AbstractServerMembers
|
+ 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 {
|
impl From<crate::File> for File {
|
||||||
fn from(value: crate::File) -> Self {
|
fn from(value: crate::File) -> Self {
|
||||||
File {
|
File {
|
||||||
|
|||||||
33
crates/core/models/src/v0/emojis.rs
Normal file
33
crates/core/models/src/v0/emojis.rs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
auto_derived!(
|
||||||
|
/// Emoji
|
||||||
|
pub struct Emoji {
|
||||||
|
/// Unique Id
|
||||||
|
#[cfg_attr(feature = "serde", 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
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "serde",
|
||||||
|
serde(skip_serializing_if = "crate::if_false", default)
|
||||||
|
)]
|
||||||
|
pub animated: bool,
|
||||||
|
/// Whether the emoji is marked as nsfw
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "serde",
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -3,9 +3,11 @@ mod channel_invites;
|
|||||||
mod channel_unreads;
|
mod channel_unreads;
|
||||||
mod channel_webhooks;
|
mod channel_webhooks;
|
||||||
mod channels;
|
mod channels;
|
||||||
|
mod emojis;
|
||||||
mod files;
|
mod files;
|
||||||
mod server_members;
|
mod server_members;
|
||||||
mod servers;
|
mod servers;
|
||||||
|
mod user_settings;
|
||||||
mod users;
|
mod users;
|
||||||
|
|
||||||
pub use bots::*;
|
pub use bots::*;
|
||||||
@@ -13,7 +15,9 @@ pub use channel_invites::*;
|
|||||||
pub use channel_unreads::*;
|
pub use channel_unreads::*;
|
||||||
pub use channel_webhooks::*;
|
pub use channel_webhooks::*;
|
||||||
pub use channels::*;
|
pub use channels::*;
|
||||||
|
pub use emojis::*;
|
||||||
pub use files::*;
|
pub use files::*;
|
||||||
pub use server_members::*;
|
pub use server_members::*;
|
||||||
pub use servers::*;
|
pub use servers::*;
|
||||||
|
pub use user_settings::*;
|
||||||
pub use users::*;
|
pub use users::*;
|
||||||
|
|||||||
6
crates/core/models/src/v0/user_settings.rs
Normal file
6
crates/core/models/src/v0/user_settings.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// HashMap of user settings
|
||||||
|
/// Each key is mapped to a tuple consisting of the
|
||||||
|
/// revision timestamp and serialised data (in JSON format)
|
||||||
|
pub type UserSettings = HashMap<String, (i64, String)>;
|
||||||
Reference in New Issue
Block a user