-
-
Notifications
You must be signed in to change notification settings - Fork 125
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
closes #273
- Loading branch information
Showing
14 changed files
with
806 additions
and
11 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,36 +3,40 @@ name = "revolt-database" | |
version = "0.6.5" | ||
edition = "2021" | ||
license = "AGPL-3.0-or-later" | ||
authors = [ "Paul Makles <[email protected]>" ] | ||
authors = ["Paul Makles <[email protected]>"] | ||
description = "Revolt Backend: Database Implementation" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[features] | ||
# Databases | ||
mongodb = [ "dep:mongodb", "bson" ] | ||
mongodb = ["dep:mongodb", "bson"] | ||
|
||
# ... Other | ||
async-std-runtime = [ "async-std" ] | ||
rocket-impl = [ "rocket", "schemars" ] | ||
redis-is-patched = [ "revolt-presence/redis-is-patched" ] | ||
async-std-runtime = ["async-std"] | ||
rocket-impl = ["rocket", "schemars"] | ||
redis-is-patched = ["revolt-presence/redis-is-patched"] | ||
|
||
# Default Features | ||
default = [ "mongodb", "async-std-runtime" ] | ||
default = ["mongodb", "async-std-runtime"] | ||
|
||
[dependencies] | ||
# Core | ||
revolt-result = { version = "0.6.5", path = "../result" } | ||
revolt-models = { version = "0.6.5", path = "../models" } | ||
revolt-presence = { version = "0.6.5", path = "../presence" } | ||
revolt-permissions = { version = "0.6.5", path = "../permissions", features = [ "serde", "bson" ] } | ||
revolt-permissions = { version = "0.6.5", path = "../permissions", features = [ | ||
"serde", | ||
"bson", | ||
] } | ||
|
||
# Utility | ||
log = "0.4" | ||
rand = "0.8.5" | ||
ulid = "1.0.0" | ||
nanoid = "0.4.0" | ||
once_cell = "1.17" | ||
indexmap = "1.9.1" | ||
|
||
# Serialisation | ||
serde_json = "1" | ||
|
@@ -61,7 +65,9 @@ async-std = { version = "1.8.0", features = ["attributes"], optional = true } | |
|
||
# Rocket Impl | ||
schemars = { version = "0.8.8", optional = true } | ||
rocket = { version = "0.5.0-rc.2", default-features = false, features = ["json"], optional = true } | ||
rocket = { version = "0.5.0-rc.2", default-features = false, features = [ | ||
"json", | ||
], optional = true } | ||
|
||
# Authifier | ||
authifier = { version = "1.0" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
mod model; | ||
mod ops; | ||
|
||
pub use model::*; | ||
pub use ops::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
use indexmap::{IndexMap, IndexSet}; | ||
use iso8601_timestamp::Timestamp; | ||
use revolt_models::v0::{Embed, MessageSort, MessageWebhook}; | ||
|
||
use crate::File; | ||
|
||
auto_derived_partial!( | ||
/// Message | ||
pub struct Message { | ||
/// Unique Id | ||
#[serde(rename = "_id")] | ||
pub id: String, | ||
/// Unique value generated by client sending this message | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub nonce: Option<String>, | ||
/// Id of the channel this message was sent in | ||
pub channel: String, | ||
/// Id of the user or webhook that sent this message | ||
pub author: String, | ||
/// The webhook that sent this message | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub webhook: Option<MessageWebhook>, | ||
/// Message content | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub content: Option<String>, | ||
/// System message | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub system: Option<SystemMessage>, | ||
/// Array of attachments | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub attachments: Option<Vec<File>>, | ||
/// Time at which this message was last edited | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub edited: Option<Timestamp>, | ||
/// Attached embeds to this message | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub embeds: Option<Vec<Embed>>, | ||
/// Array of user ids mentioned in this message | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub mentions: Option<Vec<String>>, | ||
/// Array of message ids this message is replying to | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub replies: Option<Vec<String>>, | ||
/// Hashmap of emoji IDs to array of user IDs | ||
#[serde(skip_serializing_if = "IndexMap::is_empty", default)] | ||
pub reactions: IndexMap<String, IndexSet<String>>, | ||
/// Information about how this message should be interacted with | ||
#[serde(skip_serializing_if = "Interactions::is_default", default)] | ||
pub interactions: Interactions, | ||
/// Name and / or avatar overrides for this message | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub masquerade: Option<Masquerade>, | ||
}, | ||
"PartialMessage" | ||
); | ||
|
||
auto_derived!( | ||
/// System Event | ||
#[serde(tag = "type")] | ||
pub enum SystemMessage { | ||
#[serde(rename = "text")] | ||
Text { content: String }, | ||
#[serde(rename = "user_added")] | ||
UserAdded { id: String, by: String }, | ||
#[serde(rename = "user_remove")] | ||
UserRemove { id: String, by: String }, | ||
#[serde(rename = "user_joined")] | ||
UserJoined { id: String }, | ||
#[serde(rename = "user_left")] | ||
UserLeft { id: String }, | ||
#[serde(rename = "user_kicked")] | ||
UserKicked { id: String }, | ||
#[serde(rename = "user_banned")] | ||
UserBanned { id: String }, | ||
#[serde(rename = "channel_renamed")] | ||
ChannelRenamed { name: String, by: String }, | ||
#[serde(rename = "channel_description_changed")] | ||
ChannelDescriptionChanged { by: String }, | ||
#[serde(rename = "channel_icon_changed")] | ||
ChannelIconChanged { by: String }, | ||
#[serde(rename = "channel_ownership_changed")] | ||
ChannelOwnershipChanged { from: String, to: String }, | ||
} | ||
|
||
/// Name and / or avatar override information | ||
pub struct Masquerade { | ||
/// Replace the display name shown on this message | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub name: Option<String>, | ||
/// Replace the avatar shown on this message (URL to image file) | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub avatar: Option<String>, | ||
/// Replace the display role colour shown on this message | ||
/// | ||
/// Must have `ManageRole` permission to use | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub colour: Option<String>, | ||
} | ||
|
||
/// Information to guide interactions on this message | ||
#[derive(Default)] | ||
pub struct Interactions { | ||
/// Reactions which should always appear and be distinct | ||
#[serde(skip_serializing_if = "Option::is_none", default)] | ||
pub reactions: Option<IndexSet<String>>, | ||
/// Whether reactions should be restricted to the given list | ||
/// | ||
/// Can only be set to true if reactions list is of at least length 1 | ||
#[serde(skip_serializing_if = "crate::if_false", default)] | ||
pub restrict_reactions: bool, | ||
} | ||
|
||
/// Appended Information | ||
pub struct AppendMessage { | ||
/// Additional embeds to include in this message | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub embeds: Option<Vec<Embed>>, | ||
} | ||
|
||
/// Message Time Period | ||
/// | ||
/// Filter and sort messages by time | ||
#[serde(untagged)] | ||
pub enum MessageTimePeriod { | ||
Relative { | ||
/// Message id to search around | ||
/// | ||
/// Specifying 'nearby' ignores 'before', 'after' and 'sort'. | ||
/// It will also take half of limit rounded as the limits to each side. | ||
/// It also fetches the message ID specified. | ||
nearby: String, | ||
}, | ||
Absolute { | ||
/// Message id before which messages should be fetched | ||
before: Option<String>, | ||
/// Message id after which messages should be fetched | ||
after: Option<String>, | ||
/// Message sort direction | ||
sort: Option<MessageSort>, | ||
}, | ||
} | ||
|
||
/// Message Filter | ||
pub struct MessageFilter { | ||
/// Parent channel ID | ||
pub channel: Option<String>, | ||
/// Message author ID | ||
pub author: Option<String>, | ||
/// Search query | ||
pub query: Option<String>, | ||
} | ||
|
||
/// Message Query | ||
pub struct MessageQuery { | ||
/// Maximum number of messages to fetch | ||
/// | ||
/// For fetching nearby messages, this is \`(limit + 1)\`. | ||
pub limit: Option<i64>, | ||
/// Filter to apply | ||
#[serde(flatten)] | ||
pub filter: MessageFilter, | ||
/// Time period to fetch | ||
#[serde(flatten)] | ||
pub time_period: MessageTimePeriod, | ||
} | ||
); | ||
|
||
#[allow(clippy::disallowed_methods)] | ||
impl Message {} | ||
|
||
impl Interactions { | ||
/// Validate interactions info is correct | ||
/* pub async fn validate( | ||
&self, | ||
db: &Database, | ||
permissions: &mut PermissionCalculator<'_>, | ||
) -> Result<()> { | ||
if let Some(reactions) = &self.reactions { | ||
permissions.throw_permission(db, Permission::React).await?; | ||
if reactions.len() > 20 { | ||
return Err(Error::InvalidOperation); | ||
} | ||
for reaction in reactions { | ||
if !Emoji::can_use(db, reaction).await? { | ||
return Err(Error::InvalidOperation); | ||
} | ||
} | ||
} | ||
Ok(()) | ||
}*/ | ||
|
||
/// Check if we can use a given emoji to react | ||
pub fn can_use(&self, emoji: &str) -> bool { | ||
if self.restrict_reactions { | ||
if let Some(reactions) = &self.reactions { | ||
reactions.contains(emoji) | ||
} else { | ||
false | ||
} | ||
} else { | ||
true | ||
} | ||
} | ||
|
||
/// Check if default initialisation of fields | ||
pub fn is_default(&self) -> bool { | ||
!self.restrict_reactions && self.reactions.is_none() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
use revolt_result::Result; | ||
|
||
use crate::{AppendMessage, Message, MessageQuery, PartialMessage}; | ||
|
||
// mod mongodb; | ||
// mod reference; | ||
|
||
#[async_trait] | ||
pub trait AbstractMessages: Sync + Send { | ||
/// Insert a new message into the database | ||
async fn insert_message(&self, message: &Message) -> Result<()>; | ||
|
||
/// Fetch a message by its id | ||
async fn fetch_message(&self, id: &str) -> Result<Message>; | ||
|
||
/// Fetch multiple messages by given query | ||
async fn fetch_messages(&self, query: MessageQuery) -> Result<Vec<Message>>; | ||
|
||
/// Update a given message with new information | ||
async fn update_message(&self, id: &str, message: &PartialMessage) -> Result<()>; | ||
|
||
/// Append information to a given message | ||
async fn append_message(&self, id: &str, append: &AppendMessage) -> Result<()>; | ||
|
||
/// Add a new reaction to a message | ||
async fn add_reaction(&self, id: &str, emoji: &str, user: &str) -> Result<()>; | ||
|
||
/// Remove a reaction from a message | ||
async fn remove_reaction(&self, id: &str, emoji: &str, user: &str) -> Result<()>; | ||
|
||
/// Remove reaction from a message | ||
async fn clear_reaction(&self, id: &str, emoji: &str) -> Result<()>; | ||
|
||
/// Delete a message from the database by its id | ||
async fn delete_message(&self, id: &str) -> Result<()>; | ||
|
||
/// Delete messages from a channel by their ids and corresponding channel id | ||
async fn delete_messages(&self, channel: &str, ids: Vec<String>) -> Result<()>; | ||
} |
Oops, something went wrong.