feat(core): implement message db methods
This commit is contained in:
@@ -4,7 +4,7 @@ use futures::lock::Mutex;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Bot, Channel, ChannelCompositeKey, ChannelUnread, Emoji, File, Invite, Member,
|
Bot, Channel, ChannelCompositeKey, ChannelUnread, Emoji, File, Invite, Member,
|
||||||
MemberCompositeKey, Server, ServerBan, User, UserSettings, Webhook,
|
MemberCompositeKey, Message, Server, ServerBan, User, UserSettings, Webhook,
|
||||||
};
|
};
|
||||||
|
|
||||||
database_derived!(
|
database_derived!(
|
||||||
@@ -17,14 +17,14 @@ database_derived!(
|
|||||||
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 emojis: Arc<Mutex<HashMap<String, Emoji>>>,
|
||||||
|
pub files: Arc<Mutex<HashMap<String, File>>>,
|
||||||
|
pub messages: Arc<Mutex<HashMap<String, Message>>>,
|
||||||
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_bans: Arc<Mutex<HashMap<MemberCompositeKey, ServerBan>>>,
|
pub server_bans: Arc<Mutex<HashMap<MemberCompositeKey, ServerBan>>>,
|
||||||
pub server_members: Arc<Mutex<HashMap<MemberCompositeKey, Member>>>,
|
pub server_members: Arc<Mutex<HashMap<MemberCompositeKey, Member>>>,
|
||||||
pub servers: Arc<Mutex<HashMap<String, Server>>>,
|
pub servers: Arc<Mutex<HashMap<String, Server>>>,
|
||||||
pub files: Arc<Mutex<HashMap<String, File>>>,
|
|
||||||
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 messages: Arc<Mutex<HashMap<String, ()>>>,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ use authifier::AuthifierEvent;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use revolt_models::v0::{
|
use revolt_models::v0::{
|
||||||
Channel, Emoji, FieldsChannel, FieldsMember, FieldsRole, FieldsServer, FieldsUser,
|
AppendMessage, Channel, Emoji, FieldsChannel, FieldsMember, FieldsRole, FieldsServer,
|
||||||
FieldsWebhook, MemberCompositeKey, PartialChannel, PartialMember, PartialRole, PartialServer,
|
FieldsUser, FieldsWebhook, MemberCompositeKey, Message, PartialChannel, PartialMember,
|
||||||
PartialUser, PartialWebhook, Server, UserSettings, Webhook,
|
PartialMessage, PartialRole, PartialServer, PartialUser, PartialWebhook, Server, UserSettings,
|
||||||
|
Webhook,
|
||||||
};
|
};
|
||||||
use revolt_result::Error;
|
use revolt_result::Error;
|
||||||
|
|
||||||
@@ -57,8 +58,7 @@ pub enum EventV1 {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/// Ping response
|
/// Ping response
|
||||||
Pong { data: Ping },
|
Pong { data: Ping }, */
|
||||||
|
|
||||||
/// New message
|
/// New message
|
||||||
Message(Message),
|
Message(Message),
|
||||||
|
|
||||||
@@ -103,7 +103,8 @@ pub enum EventV1 {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/// Bulk delete messages
|
/// Bulk delete messages
|
||||||
BulkMessageDelete { channel: String, ids: Vec<String> },*/
|
BulkMessageDelete { channel: String, ids: Vec<String> },
|
||||||
|
|
||||||
/// New server
|
/// New server
|
||||||
ServerCreate {
|
ServerCreate {
|
||||||
id: String,
|
id: String,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
use iso8601_timestamp::Timestamp;
|
use iso8601_timestamp::Timestamp;
|
||||||
use revolt_models::v0::{Embed, MessageSort, MessageWebhook};
|
use revolt_models::v0::{Embed, MessageSort, MessageWebhook};
|
||||||
use revolt_result::{create_error, Result};
|
use revolt_result::Result;
|
||||||
|
|
||||||
use crate::{Database, File};
|
use crate::{events::client::EventV1, Database, File};
|
||||||
|
|
||||||
auto_derived_partial!(
|
auto_derived_partial!(
|
||||||
/// Message
|
/// Message
|
||||||
@@ -170,11 +170,26 @@ auto_derived!(
|
|||||||
impl Message {
|
impl Message {
|
||||||
/// Send a message without any notifications
|
/// Send a message without any notifications
|
||||||
pub async fn send_without_notifications(&mut self, db: &Database) -> Result<()> {
|
pub async fn send_without_notifications(&mut self, db: &Database) -> Result<()> {
|
||||||
todo!()
|
db.insert_message(self).await?;
|
||||||
|
|
||||||
|
// Fan out events
|
||||||
|
EventV1::Message(self.clone().into())
|
||||||
|
.p(self.channel.to_string())
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// TODO: update last_message_id
|
||||||
|
// TODO: add mentions for affected users
|
||||||
|
// TODO: generate embeds
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a message
|
/// Send a message
|
||||||
pub async fn send(&mut self) -> Result<()> {
|
pub async fn send(&mut self, db: &Database) -> Result<()> {
|
||||||
|
self.send_without_notifications(db).await?;
|
||||||
|
|
||||||
|
// TODO: web push / FCM
|
||||||
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ use revolt_result::Result;
|
|||||||
|
|
||||||
use crate::{AppendMessage, Message, MessageQuery, PartialMessage};
|
use crate::{AppendMessage, Message, MessageQuery, PartialMessage};
|
||||||
|
|
||||||
// mod mongodb;
|
mod mongodb;
|
||||||
// mod reference;
|
mod reference;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait AbstractMessages: Sync + Send {
|
pub trait AbstractMessages: Sync + Send {
|
||||||
@@ -35,5 +35,5 @@ pub trait AbstractMessages: Sync + Send {
|
|||||||
async fn delete_message(&self, id: &str) -> Result<()>;
|
async fn delete_message(&self, id: &str) -> Result<()>;
|
||||||
|
|
||||||
/// Delete messages from a channel by their ids and corresponding channel id
|
/// Delete messages from a channel by their ids and corresponding channel id
|
||||||
async fn delete_messages(&self, channel: &str, ids: Vec<String>) -> Result<()>;
|
async fn delete_messages(&self, channel: &str, ids: &[String]) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +1,214 @@
|
|||||||
use bson::Document;
|
use bson::{to_bson, Document};
|
||||||
|
use futures::try_join;
|
||||||
|
use mongodb::options::FindOptions;
|
||||||
|
use revolt_models::v0::MessageSort;
|
||||||
use revolt_result::Result;
|
use revolt_result::Result;
|
||||||
|
|
||||||
use crate::Emoji;
|
use crate::{AppendMessage, Message, MessageQuery, MessageTimePeriod, MongoDb, PartialMessage};
|
||||||
use crate::MongoDb;
|
|
||||||
|
|
||||||
use super::AbstractEmojis;
|
use super::AbstractMessages;
|
||||||
|
|
||||||
static COL: &str = "emojis";
|
static COL: &str = "messages";
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl AbstractEmojis for MongoDb {
|
impl AbstractMessages for MongoDb {
|
||||||
/// Insert emoji into database.
|
/// Insert a new message into the database
|
||||||
async fn insert_emoji(&self, emoji: &Emoji) -> Result<()> {
|
async fn insert_message(&self, message: &Message) -> Result<()> {
|
||||||
query!(self, insert_one, COL, &emoji).map(|_| ())
|
query!(self, insert_one, COL, &message).map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch an emoji by its id
|
/// Fetch a message by its id
|
||||||
async fn fetch_emoji(&self, id: &str) -> Result<Emoji> {
|
async fn fetch_message(&self, id: &str) -> Result<Message> {
|
||||||
query!(self, find_one_by_id, COL, id)?.ok_or_else(|| create_error!(NotFound))
|
query!(self, find_one_by_id, COL, id)?.ok_or_else(|| create_error!(NotFound))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch emoji by their parent id
|
/// Fetch multiple messages by given query
|
||||||
async fn fetch_emoji_by_parent_id(&self, parent_id: &str) -> Result<Vec<Emoji>> {
|
async fn fetch_messages(&self, query: MessageQuery) -> Result<Vec<Message>> {
|
||||||
query!(
|
let mut filter = doc! {};
|
||||||
self,
|
|
||||||
find_one,
|
|
||||||
COL,
|
|
||||||
doc! {
|
|
||||||
"parent.id": parent_id
|
|
||||||
}
|
|
||||||
)?
|
|
||||||
.ok_or_else(|| create_error!(NotFound))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fetch emoji by their parent ids
|
// 1. Apply message filters
|
||||||
async fn fetch_emoji_by_parent_ids(&self, parent_ids: &[String]) -> Result<Vec<Emoji>> {
|
if let Some(channel) = query.filter.channel {
|
||||||
query!(
|
filter.insert("channel", channel);
|
||||||
self,
|
}
|
||||||
find,
|
|
||||||
COL,
|
if let Some(author) = query.filter.author {
|
||||||
doc! {
|
filter.insert("author", author);
|
||||||
"parent.id": {
|
}
|
||||||
"$in": parent_ids
|
|
||||||
|
let is_search_query = if let Some(query) = query.filter.query {
|
||||||
|
filter.insert(
|
||||||
|
"$text",
|
||||||
|
doc! {
|
||||||
|
"$search": query
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
// 2. Find query limit
|
||||||
|
let limit = query.limit.unwrap_or(50);
|
||||||
|
|
||||||
|
// 3. Apply message time period
|
||||||
|
match query.time_period {
|
||||||
|
MessageTimePeriod::Relative { nearby } => {
|
||||||
|
// 3.1. Prepare filters
|
||||||
|
let mut older_message_filter = filter.clone();
|
||||||
|
let mut newer_message_filter = filter;
|
||||||
|
|
||||||
|
older_message_filter.insert(
|
||||||
|
"_id",
|
||||||
|
doc! {
|
||||||
|
"$lt": &nearby
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
newer_message_filter.insert(
|
||||||
|
"_id",
|
||||||
|
doc! {
|
||||||
|
"$gte": &nearby
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3.2. Execute in both directions
|
||||||
|
let (a, b) = try_join!(
|
||||||
|
self.find_with_options::<_, Message>(
|
||||||
|
COL,
|
||||||
|
newer_message_filter,
|
||||||
|
FindOptions::builder()
|
||||||
|
.limit(limit / 2 + 1)
|
||||||
|
.sort(doc! {
|
||||||
|
"_id": 1_i32
|
||||||
|
})
|
||||||
|
.build(),
|
||||||
|
),
|
||||||
|
self.find_with_options::<_, Message>(
|
||||||
|
COL,
|
||||||
|
older_message_filter,
|
||||||
|
FindOptions::builder()
|
||||||
|
.limit(limit / 2)
|
||||||
|
.sort(doc! {
|
||||||
|
"_id": -1_i32
|
||||||
|
})
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.map_err(|_| create_database_error!("find", COL))?;
|
||||||
|
|
||||||
|
Ok([a, b].concat())
|
||||||
|
}
|
||||||
|
MessageTimePeriod::Absolute {
|
||||||
|
before,
|
||||||
|
after,
|
||||||
|
sort,
|
||||||
|
} => {
|
||||||
|
// 3.1. Apply message ID filter
|
||||||
|
if let Some(doc) = match (before, after) {
|
||||||
|
(Some(before), Some(after)) => Some(doc! {
|
||||||
|
"$lt": before,
|
||||||
|
"$gt": after
|
||||||
|
}),
|
||||||
|
(Some(before), _) => Some(doc! {
|
||||||
|
"$lt": before
|
||||||
|
}),
|
||||||
|
(_, Some(after)) => Some(doc! {
|
||||||
|
"$gt": after
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
} {
|
||||||
|
filter.insert("_id", doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3.2. Execute with given message sort
|
||||||
|
self.find_with_options(
|
||||||
|
COL,
|
||||||
|
filter,
|
||||||
|
FindOptions::builder()
|
||||||
|
.limit(limit)
|
||||||
|
.sort(match sort.unwrap_or(MessageSort::Latest) {
|
||||||
|
// Sort by relevance, fallback to latest
|
||||||
|
MessageSort::Relevance => {
|
||||||
|
if is_search_query {
|
||||||
|
doc! {
|
||||||
|
"score": {
|
||||||
|
"$meta": "textScore"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
doc! {
|
||||||
|
"_id": -1_i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sort by latest first
|
||||||
|
MessageSort::Latest => doc! {
|
||||||
|
"_id": -1_i32
|
||||||
|
},
|
||||||
|
// Sort by oldest first
|
||||||
|
MessageSort::Oldest => doc! {
|
||||||
|
"_id": 1_i32
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| create_database_error!("find", COL))
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Detach an emoji by its id
|
/// Update a given message with new information
|
||||||
async fn detach_emoji(&self, emoji: &Emoji) -> Result<()> {
|
async fn update_message(&self, id: &str, message: &PartialMessage) -> Result<()> {
|
||||||
|
query!(self, update_one_by_id, COL, id, message, vec![], None).map(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append information to a given message
|
||||||
|
async fn append_message(&self, id: &str, append: &AppendMessage) -> Result<()> {
|
||||||
|
let mut query = doc! {};
|
||||||
|
|
||||||
|
if let Some(embeds) = &append.embeds {
|
||||||
|
if !embeds.is_empty() {
|
||||||
|
query.insert(
|
||||||
|
"$push",
|
||||||
|
doc! {
|
||||||
|
"embeds": {
|
||||||
|
"$each": to_bson(embeds)
|
||||||
|
.map_err(|_| create_database_error!("to_bson", "embeds"))?
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if query.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
self.col::<Document>(COL)
|
self.col::<Document>(COL)
|
||||||
.update_one(
|
.update_one(
|
||||||
doc! {
|
doc! {
|
||||||
"_id": &emoji.id
|
"_id": id
|
||||||
|
},
|
||||||
|
query,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(|_| create_database_error!("update_one", COL))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a new reaction to a message
|
||||||
|
async fn add_reaction(&self, id: &str, emoji: &str, user: &str) -> Result<()> {
|
||||||
|
self.col::<Document>(COL)
|
||||||
|
.update_one(
|
||||||
|
doc! {
|
||||||
|
"_id": id
|
||||||
},
|
},
|
||||||
doc! {
|
doc! {
|
||||||
"$set": {
|
"$addToSet": {
|
||||||
"parent": {
|
format!("reactions.{emoji}"): user
|
||||||
"type": "Detached"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
@@ -67,4 +217,64 @@ impl AbstractEmojis for MongoDb {
|
|||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err(|_| create_database_error!("update_one", COL))
|
.map_err(|_| create_database_error!("update_one", COL))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove a reaction from a message
|
||||||
|
async fn remove_reaction(&self, id: &str, emoji: &str, user: &str) -> Result<()> {
|
||||||
|
self.col::<Document>(COL)
|
||||||
|
.update_one(
|
||||||
|
doc! {
|
||||||
|
"_id": id
|
||||||
|
},
|
||||||
|
doc! {
|
||||||
|
"$pull": {
|
||||||
|
format!("reactions.{emoji}"): user
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(|_| create_database_error!("update_one", COL))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove reaction from a message
|
||||||
|
async fn clear_reaction(&self, id: &str, emoji: &str) -> Result<()> {
|
||||||
|
self.col::<Document>(COL)
|
||||||
|
.update_one(
|
||||||
|
doc! {
|
||||||
|
"_id": id
|
||||||
|
},
|
||||||
|
doc! {
|
||||||
|
"$unset": {
|
||||||
|
format!("reactions.{emoji}"): 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(|_| create_database_error!("update_one", COL))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete a message from the database by its id
|
||||||
|
async fn delete_message(&self, id: &str) -> Result<()> {
|
||||||
|
query!(self, delete_one_by_id, COL, id).map(|_| ())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete messages from a channel by their ids and corresponding channel id
|
||||||
|
async fn delete_messages(&self, channel: &str, ids: &[String]) -> Result<()> {
|
||||||
|
self.col::<Document>(COL)
|
||||||
|
.delete_many(
|
||||||
|
doc! {
|
||||||
|
"channel": channel,
|
||||||
|
"_id": {
|
||||||
|
"$in": ids
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map(|_| ())
|
||||||
|
.map_err(|_| create_database_error!("delete_many", COL))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,67 +1,272 @@
|
|||||||
|
use indexmap::IndexSet;
|
||||||
use revolt_result::Result;
|
use revolt_result::Result;
|
||||||
|
|
||||||
use crate::Emoji;
|
use crate::{AppendMessage, Message, MessageQuery, PartialMessage, ReferenceDb};
|
||||||
use crate::EmojiParent;
|
|
||||||
use crate::ReferenceDb;
|
|
||||||
|
|
||||||
use super::AbstractEmojis;
|
use super::AbstractMessages;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl AbstractEmojis for ReferenceDb {
|
impl AbstractMessages for ReferenceDb {
|
||||||
/// Insert emoji into database.
|
/// Insert a new message into the database
|
||||||
async fn insert_emoji(&self, emoji: &Emoji) -> Result<()> {
|
async fn insert_message(&self, message: &Message) -> Result<()> {
|
||||||
let mut emojis = self.emojis.lock().await;
|
let mut messages = self.messages.lock().await;
|
||||||
if emojis.contains_key(&emoji.id) {
|
if messages.contains_key(&message.id) {
|
||||||
Err(create_database_error!("insert", "emoji"))
|
Err(create_database_error!("insert", "message"))
|
||||||
} else {
|
} else {
|
||||||
emojis.insert(emoji.id.to_string(), emoji.clone());
|
messages.insert(message.id.to_string(), message.clone());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch an emoji by its id
|
/// Fetch a message by its id
|
||||||
async fn fetch_emoji(&self, id: &str) -> Result<Emoji> {
|
async fn fetch_message(&self, id: &str) -> Result<Message> {
|
||||||
let emojis = self.emojis.lock().await;
|
let messages = self.messages.lock().await;
|
||||||
emojis
|
messages
|
||||||
.get(id)
|
.get(id)
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or_else(|| create_error!(NotFound))
|
.ok_or_else(|| create_error!(NotFound))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch emoji by their parent id
|
/// Fetch multiple messages by given query
|
||||||
async fn fetch_emoji_by_parent_id(&self, parent_id: &str) -> Result<Vec<Emoji>> {
|
async fn fetch_messages(&self, query: MessageQuery) -> Result<Vec<Message>> {
|
||||||
let emojis = self.emojis.lock().await;
|
let messages = self.messages.lock().await;
|
||||||
Ok(emojis
|
let matched_messages = messages
|
||||||
.values()
|
.values()
|
||||||
.filter(|emoji| match &emoji.parent {
|
.filter(|message| {
|
||||||
EmojiParent::Server { id } => id == parent_id,
|
if let Some(channel) = &query.filter.channel {
|
||||||
_ => false,
|
if &message.channel != channel {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(author) = &query.filter.author {
|
||||||
|
if &message.author != author {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(query) = &query.filter.query {
|
||||||
|
if let Some(content) = &message.content {
|
||||||
|
if !content.to_lowercase().contains(query) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
})
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect())
|
.collect();
|
||||||
|
|
||||||
|
// TODO: sorting, etc
|
||||||
|
|
||||||
|
Ok(matched_messages)
|
||||||
|
|
||||||
|
/*
|
||||||
|
// 2. Find query limit
|
||||||
|
let limit = query.limit.unwrap_or(50);
|
||||||
|
|
||||||
|
// 3. Apply message time period
|
||||||
|
match query.time_period {
|
||||||
|
MessageTimePeriod::Relative { nearby } => {
|
||||||
|
// 3.1. Prepare filters
|
||||||
|
let mut older_message_filter = filter.clone();
|
||||||
|
let mut newer_message_filter = filter;
|
||||||
|
|
||||||
|
older_message_filter.insert(
|
||||||
|
"_id",
|
||||||
|
doc! {
|
||||||
|
"$lt": &nearby
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
newer_message_filter.insert(
|
||||||
|
"_id",
|
||||||
|
doc! {
|
||||||
|
"$gte": &nearby
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3.2. Execute in both directions
|
||||||
|
let (a, b) = try_join!(
|
||||||
|
self.find_with_options::<_, Message>(
|
||||||
|
COL,
|
||||||
|
newer_message_filter,
|
||||||
|
FindOptions::builder()
|
||||||
|
.limit(limit / 2 + 1)
|
||||||
|
.sort(doc! {
|
||||||
|
"_id": 1_i32
|
||||||
|
})
|
||||||
|
.build(),
|
||||||
|
),
|
||||||
|
self.find_with_options::<_, Message>(
|
||||||
|
COL,
|
||||||
|
older_message_filter,
|
||||||
|
FindOptions::builder()
|
||||||
|
.limit(limit / 2)
|
||||||
|
.sort(doc! {
|
||||||
|
"_id": -1_i32
|
||||||
|
})
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.map_err(|_| create_database_error!("find", COL))?;
|
||||||
|
|
||||||
|
Ok([a, b].concat())
|
||||||
|
}
|
||||||
|
MessageTimePeriod::Absolute {
|
||||||
|
before,
|
||||||
|
after,
|
||||||
|
sort,
|
||||||
|
} => {
|
||||||
|
// 3.1. Apply message ID filter
|
||||||
|
if let Some(doc) = match (before, after) {
|
||||||
|
(Some(before), Some(after)) => Some(doc! {
|
||||||
|
"$lt": before,
|
||||||
|
"$gt": after
|
||||||
|
}),
|
||||||
|
(Some(before), _) => Some(doc! {
|
||||||
|
"$lt": before
|
||||||
|
}),
|
||||||
|
(_, Some(after)) => Some(doc! {
|
||||||
|
"$gt": after
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
} {
|
||||||
|
filter.insert("_id", doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.2. Execute with given message sort
|
||||||
|
self.find_with_options(
|
||||||
|
COL,
|
||||||
|
filter,
|
||||||
|
FindOptions::builder()
|
||||||
|
.limit(limit)
|
||||||
|
.sort(match sort.unwrap_or(MessageSort::Latest) {
|
||||||
|
// Sort by relevance, fallback to latest
|
||||||
|
MessageSort::Relevance => {
|
||||||
|
if is_search_query {
|
||||||
|
doc! {
|
||||||
|
"score": {
|
||||||
|
"$meta": "textScore"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
doc! {
|
||||||
|
"_id": -1_i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sort by latest first
|
||||||
|
MessageSort::Latest => doc! {
|
||||||
|
"_id": -1_i32
|
||||||
|
},
|
||||||
|
// Sort by oldest first
|
||||||
|
MessageSort::Oldest => doc! {
|
||||||
|
"_id": 1_i32
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| create_database_error!("find", COL))
|
||||||
|
}
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch emoji by their parent ids
|
/// Update a given message with new information
|
||||||
async fn fetch_emoji_by_parent_ids(&self, parent_ids: &[String]) -> Result<Vec<Emoji>> {
|
async fn update_message(&self, id: &str, message: &PartialMessage) -> Result<()> {
|
||||||
let emojis = self.emojis.lock().await;
|
let mut messages = self.messages.lock().await;
|
||||||
Ok(emojis
|
if let Some(message_data) = messages.get_mut(id) {
|
||||||
.values()
|
message_data.apply_options(message.to_owned());
|
||||||
.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(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(create_error!(NotFound))
|
Err(create_error!(NotFound))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Append information to a given message
|
||||||
|
async fn append_message(&self, id: &str, append: &AppendMessage) -> Result<()> {
|
||||||
|
let mut messages = self.messages.lock().await;
|
||||||
|
if let Some(message_data) = messages.get_mut(id) {
|
||||||
|
if let Some(embeds) = &append.embeds {
|
||||||
|
if !embeds.is_empty() {
|
||||||
|
if let Some(embeds_data) = &mut message_data.embeds {
|
||||||
|
embeds_data.extend(embeds.clone());
|
||||||
|
} else {
|
||||||
|
message_data.embeds = Some(embeds.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(create_error!(NotFound))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a new reaction to a message
|
||||||
|
async fn add_reaction(&self, id: &str, emoji: &str, user: &str) -> Result<()> {
|
||||||
|
let mut messages = self.messages.lock().await;
|
||||||
|
if let Some(message) = messages.get_mut(id) {
|
||||||
|
if let Some(users) = message.reactions.get_mut(emoji) {
|
||||||
|
users.insert(user.to_string());
|
||||||
|
} else {
|
||||||
|
message
|
||||||
|
.reactions
|
||||||
|
.insert(emoji.to_string(), IndexSet::from([user.to_string()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(create_error!(NotFound))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a reaction from a message
|
||||||
|
async fn remove_reaction(&self, id: &str, emoji: &str, user: &str) -> Result<()> {
|
||||||
|
let mut messages = self.messages.lock().await;
|
||||||
|
if let Some(message) = messages.get_mut(id) {
|
||||||
|
if let Some(users) = message.reactions.get_mut(emoji) {
|
||||||
|
users.remove(&user.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(create_error!(NotFound))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove reaction from a message
|
||||||
|
async fn clear_reaction(&self, id: &str, emoji: &str) -> Result<()> {
|
||||||
|
let mut messages = self.messages.lock().await;
|
||||||
|
if let Some(message) = messages.get_mut(id) {
|
||||||
|
message.reactions.remove(emoji);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(create_error!(NotFound))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete a message from the database by its id
|
||||||
|
async fn delete_message(&self, id: &str) -> Result<()> {
|
||||||
|
let mut messages = self.messages.lock().await;
|
||||||
|
if messages.remove(id).is_some() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(create_error!(NotFound))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete messages from a channel by their ids and corresponding channel id
|
||||||
|
async fn delete_messages(&self, channel: &str, ids: &[String]) -> Result<()> {
|
||||||
|
self.messages
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.retain(|id, message| message.channel != channel && !ids.contains(id));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ pub trait AbstractDatabase:
|
|||||||
+ channel_webhooks::AbstractWebhooks
|
+ channel_webhooks::AbstractWebhooks
|
||||||
+ emojis::AbstractEmojis
|
+ emojis::AbstractEmojis
|
||||||
+ files::AbstractAttachments
|
+ files::AbstractAttachments
|
||||||
|
+ messages::AbstractMessages
|
||||||
+ ratelimit_events::AbstractRatelimitEvents
|
+ ratelimit_events::AbstractRatelimitEvents
|
||||||
+ server_bans::AbstractServerBans
|
+ server_bans::AbstractServerBans
|
||||||
+ server_members::AbstractServerMembers
|
+ server_members::AbstractServerMembers
|
||||||
|
|||||||
Reference in New Issue
Block a user