feat: add emoji

This commit is contained in:
Paul Makles
2022-07-07 13:23:31 +01:00
parent 386f027a5a
commit a7e0c42ee4
28 changed files with 453 additions and 24 deletions

View File

@@ -5,7 +5,7 @@ use crate::models::message::{AppendMessage, PartialMessage};
use crate::models::server::{FieldsRole, FieldsServer, PartialRole, PartialServer};
use crate::models::server_member::{FieldsMember, MemberCompositeKey, PartialMember};
use crate::models::user::{FieldsUser, PartialUser, RelationshipStatus};
use crate::models::{Channel, Member, Message, Server, User, UserSettings};
use crate::models::{Channel, Emoji, Member, Message, Server, User, UserSettings};
use crate::Error;
/// WebSocket Client Errors
@@ -52,6 +52,7 @@ pub enum EventV1 {
servers: Vec<Server>,
channels: Vec<Channel>,
members: Vec<Member>,
emojis: Option<Vec<Emoji>>,
},
/// Ping response
@@ -170,4 +171,10 @@ pub enum EventV1 {
/// Settings updated remotely
UserSettingsUpdate { id: String, update: UserSettings },
/// New emoji
EmojiCreate(Emoji),
/// Delete emoji
EmojiDelete { id: String },
}

View File

@@ -151,6 +151,17 @@ impl State {
)
.await?;
// Fetch customisations.
let emojis = Some(
db.fetch_emoji_by_parent_ids(
&servers
.iter()
.map(|x| x.id.to_string())
.collect::<Vec<String>>(),
)
.await?,
);
// Copy data into local state cache.
self.cache.users = users.iter().cloned().map(|x| (x.id.clone(), x)).collect();
self.cache
@@ -202,6 +213,7 @@ impl State {
servers,
channels,
members,
emojis,
})
}

View File

@@ -0,0 +1,41 @@
use crate::models::emoji::EmojiParent;
use crate::models::Emoji;
use crate::{AbstractEmoji, Result};
use super::super::DummyDb;
#[async_trait]
impl AbstractEmoji for DummyDb {
/// Fetch an emoji by its id
async fn fetch_emoji(&self, id: &str) -> Result<Emoji> {
Ok(Emoji {
id: id.into(),
name: id.into(),
parent: EmojiParent::Server { id: id.into() },
creator_id: id.into(),
animated: false,
})
}
/// Fetch emoji by their ids
async fn fetch_emoji_by_parent_id(&self, parent_id: &str) -> Result<Vec<Emoji>> {
Ok(vec![self.fetch_emoji(parent_id).await?])
}
/// Fetch emoji by their parent ids
async fn fetch_emoji_by_parent_ids(&self, _parent_ids: &[String]) -> Result<Vec<Emoji>> {
Ok(vec![])
}
/// Insert emoji into database.
async fn insert_emoji(&self, emoji: &Emoji) -> Result<()> {
info!("Insert {emoji:?}");
Ok(())
}
/// Delete an emoji by its id
async fn delete_emoji(&self, emoji: &Emoji) -> Result<()> {
info!("Delete {emoji:?}");
Ok(())
}
}

View File

@@ -6,6 +6,7 @@ pub mod admin {
pub mod media {
pub mod attachment;
pub mod emoji;
}
pub mod channels {

View File

@@ -30,4 +30,9 @@ impl File {
db.find_and_use_attachment(id, "banners", "server", parent)
.await
}
pub async fn use_emoji(db: &Database, id: &str, parent: &str) -> Result<File> {
db.find_and_use_attachment(id, "emojis", "object", parent)
.await
}
}

View File

@@ -0,0 +1,36 @@
use crate::{
events::client::EventV1,
models::{emoji::EmojiParent, Emoji},
Database, Result,
};
impl Emoji {
/// Get parent id
fn parent(&self) -> &str {
match &self.parent {
EmojiParent::Server { id } => id,
}
}
/// Create an emoji
pub async fn create(&self, db: &Database) -> Result<()> {
db.insert_emoji(self).await?;
EventV1::EmojiCreate(self.clone())
.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.mark_attachment_as_deleted(&self.id).await?;
db.delete_emoji(&self).await
}
}

View File

@@ -6,6 +6,7 @@ pub mod admin {
pub mod media {
pub mod attachment;
pub mod emoji;
}
pub mod channels {

View File

@@ -16,7 +16,7 @@ struct MigrationInfo {
revision: i32,
}
pub const LATEST_REVISION: i32 = 16;
pub const LATEST_REVISION: i32 = 17;
pub async fn migrate_database(db: &MongoDb) {
let migrations = db.col::<Document>("migrations");
@@ -611,6 +611,39 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
.unwrap();
}
if revision <= 16 {
info!("Running migration [revision 16 / 07-07-2022]: Add `emojis` collection and rAuth migration.");
let rauth_db = rauth::Database::MongoDb(rauth::database::MongoDb(db.db()));
rauth_db
.run_migration(rauth::Migration::M2022_06_09AddIndexForDeletion)
.await
.unwrap();
db.db()
.create_collection("emojis", None)
.await
.expect("Failed to create emojis collection.");
db.db()
.run_command(
doc! {
"createIndexes": "emojis",
"indexes": [
{
"key": {
"parent.id": 1_i32,
},
"name": "parent_id"
}
]
},
None,
)
.await
.expect("Failed to create emoji parent index.");
}
// Need to migrate fields on attachments, change `user_id`, `object_id`, etc to `parent`.
// Reminder to update LATEST_REVISION when adding new migrations.

View File

@@ -0,0 +1,48 @@
use crate::models::Emoji;
use crate::{AbstractEmoji, Result};
use super::super::MongoDb;
static COL: &str = "emojis";
#[async_trait]
impl AbstractEmoji for MongoDb {
/// Fetch an emoji by its id
async fn fetch_emoji(&self, id: &str) -> Result<Emoji> {
self.find_one_by_id(COL, id).await
}
/// Fetch emoji by their ids
async fn fetch_emoji_by_parent_id(&self, parent_id: &str) -> Result<Vec<Emoji>> {
self.find(
COL,
doc! {
"parent.id": parent_id
},
)
.await
}
/// Fetch emoji by their parent ids
async fn fetch_emoji_by_parent_ids(&self, parent_ids: &[String]) -> Result<Vec<Emoji>> {
self.find(
COL,
doc! {
"parent.id": {
"$in": parent_ids
}
},
)
.await
}
/// Insert emoji into database.
async fn insert_emoji(&self, emoji: &Emoji) -> Result<()> {
self.insert_one(COL, emoji).await.map(|_| ())
}
/// Delete an emoji by its id
async fn delete_emoji(&self, emoji: &Emoji) -> Result<()> {
self.delete_one_by_id(COL, &emoji.id).await.map(|_| ())
}
}

View File

@@ -17,6 +17,7 @@ pub mod admin {
pub mod media {
pub mod attachment;
pub mod emoji;
}
pub mod channels {

View File

@@ -18,6 +18,20 @@ impl MongoDb {
})
.await?;
// Delete all emoji.
self.col::<Document>("emojis")
.delete_many(
doc! {
"parent.id": &server.id
},
None,
)
.await
.map_err(|_| Error::DatabaseError {
operation: "delete_many",
with: "emojis",
})?;
// Delete all channels.
self.col::<Document>("channels")
.delete_many(

View File

@@ -0,0 +1,24 @@
use serde::{Deserialize, Serialize};
/// Information about what owns this emoji
#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone)]
#[serde(tag = "type")]
pub enum EmojiParent {
Server { id: String },
}
/// Representation of an Emoji on Revolt
#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone)]
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
pub animated: bool,
}

View File

@@ -5,6 +5,7 @@ mod admin {
mod media {
pub mod attachment;
pub mod emoji;
}
mod channels {
@@ -37,6 +38,7 @@ pub use bot::Bot;
pub use channel::Channel;
pub use channel_invite::Invite;
pub use channel_unread::ChannelUnread;
pub use emoji::Emoji;
pub use message::Message;
pub use migrations::MigrationInfo;
pub use server::Server;

View File

@@ -21,8 +21,10 @@ pub enum Permission {
ManagePermissions = 1 << 2,
/// Manage roles on server
ManageRole = 1 << 3,
/// Manage server customisation (includes emoji)
ManageCustomisation = 1 << 4,
// % 2 bits reserved
// % 1 bits reserved
// * Member permissions
/// Kick other members below their ranking
@@ -122,6 +124,7 @@ bitfield! {
pub can_manage_server, _: 62;
pub can_manage_permissions, _: 61;
pub can_manage_roles, _: 60;
pub can_manage_customisation, _: 59;
// * Member permissions
pub can_kick_members, _: 57;

View File

@@ -3,6 +3,7 @@ use crate::Result;
#[async_trait]
pub trait AbstractAttachment: Sync + Send {
/// Find an attachment by its details and mark it as used by a given parent.
async fn find_and_use_attachment(
&self,
id: &str,
@@ -10,8 +11,16 @@ pub trait AbstractAttachment: Sync + Send {
parent_type: &str,
parent_id: &str,
) -> Result<File>;
/// Insert attachment into database.
async fn insert_attachment(&self, attachment: &File) -> Result<()>;
/// Mark an attachment as having been reported.
async fn mark_attachment_as_reported(&self, id: &str) -> Result<()>;
/// Mark an attachment as having been deleted.
async fn mark_attachment_as_deleted(&self, id: &str) -> Result<()>;
/// Mark multiple attachments as having been deleted.
async fn mark_attachments_as_deleted(&self, ids: &[String]) -> Result<()>;
}

View File

@@ -0,0 +1,20 @@
use crate::models::Emoji;
use crate::Result;
#[async_trait]
pub trait AbstractEmoji: Sync + Send {
/// 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>>;
/// Insert emoji into database.
async fn insert_emoji(&self, emoji: &Emoji) -> Result<()>;
/// Delete an emoji by its id
async fn delete_emoji(&self, emoji: &Emoji) -> Result<()>;
}

View File

@@ -4,6 +4,7 @@ mod admin {
mod media {
pub mod attachment;
pub mod emoji;
}
mod channels {
@@ -28,6 +29,7 @@ mod users {
pub use admin::migrations::AbstractMigrations;
pub use media::attachment::AbstractAttachment;
pub use media::emoji::AbstractEmoji;
pub use channels::channel::AbstractChannel;
pub use channels::channel_invite::AbstractChannelInvite;
@@ -42,14 +44,12 @@ pub use users::bot::AbstractBot;
pub use users::user::AbstractUser;
pub use users::user_settings::AbstractUserSettings;
// pub trait AbstractEventEmitter {}
// + AbstractEventEmitter
pub trait AbstractDatabase:
Sync
+ Send
+ AbstractMigrations
+ AbstractAttachment
+ AbstractEmoji
+ AbstractChannel
+ AbstractChannelInvite
+ AbstractChannelUnread

View File

@@ -4,7 +4,7 @@ use schemars::schema::{InstanceType, Schema, SchemaObject, SingleOrVec};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::models::{Bot, Channel, Invite, Member, Message, Server, ServerBan, User};
use crate::models::{Bot, Channel, Emoji, Invite, Member, Message, Server, ServerBan, User};
use crate::presence::presence_is_online;
use crate::{Database, Result};
@@ -63,6 +63,11 @@ impl Ref {
pub async fn as_ban(&self, db: &Database, server: &str) -> Result<ServerBan> {
db.fetch_ban(server, &self.id).await
}
/// Fetch emoji from Ref
pub async fn as_emoji(&self, db: &Database) -> Result<Emoji> {
db.fetch_emoji(&self.id).await
}
}
impl<'r> FromParam<'r> for Ref {

View File

@@ -56,6 +56,7 @@ pub enum Error {
TooManyServers {
max: usize,
},
TooManyEmoji,
// ? Bot related errors.
ReachedMaximumBots,
@@ -156,6 +157,7 @@ impl<'r> Responder<'r, 'static> for Error {
Error::InvalidRole => Status::NotFound,
Error::Banned => Status::Forbidden,
Error::TooManyServers { .. } => Status::Forbidden,
Error::TooManyEmoji => Status::BadRequest,
Error::ReachedMaximumBots => Status::BadRequest,
Error::IsBot => Status::BadRequest,