diff --git a/src/database/guards/reference.rs b/src/database/guards/reference.rs index a71a90e936999514ada35135e9d7b8807ae8efa2..7f7a651d69e341938362af38639828330f9a798f 100644 --- a/src/database/guards/reference.rs +++ b/src/database/guards/reference.rs @@ -4,7 +4,7 @@ use crate::util::result::{Error, Result}; use validator::Validate; use rocket::http::RawStr; use rocket::request::FromParam; -use mongodb::bson::{doc, from_bson, Bson}; +use mongodb::bson::{Bson, doc, from_bson, from_document}; use serde::{Deserialize, Serialize, de::DeserializeOwned}; #[derive(Validate, Serialize, Deserialize)] @@ -34,8 +34,8 @@ impl Ref { .ok_or_else(|| Error::UnknownUser)?; Ok( - from_bson::<T>(Bson::Document(doc)).map_err(|_| Error::DatabaseError { - operation: "from_bson", + from_document::<T>(doc).map_err(|_| Error::DatabaseError { + operation: "from_document", with: &collection, })?, ) diff --git a/src/database/guards/user.rs b/src/database/guards/user.rs index 7602aefa5fa8915fb33b4415672192866bad0418..dc3d7ee5511a7dcdb21f02feaeb47332ec4ae913 100644 --- a/src/database/guards/user.rs +++ b/src/database/guards/user.rs @@ -1,6 +1,6 @@ use crate::database::*; -use mongodb::bson::{doc, from_bson, Bson}; +use mongodb::bson::{Bson, doc, from_bson, from_document}; use rauth::auth::Session; use rocket::http::Status; use rocket::request::{self, FromRequest, Outcome, Request}; @@ -22,7 +22,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for User { .await { if let Some(doc) = result { - Outcome::Success(from_bson(Bson::Document(doc)).unwrap()) + Outcome::Success(from_document(doc).unwrap()) } else { Outcome::Failure((Status::Forbidden, rauth::util::Error::InvalidSession)) } diff --git a/src/database/migrations/scripts.rs b/src/database/migrations/scripts.rs index 517241661c6cec90d07ee276a4d3e0e880732037..b5f411ba331facc090ea15d2db4830b3211e2408 100644 --- a/src/database/migrations/scripts.rs +++ b/src/database/migrations/scripts.rs @@ -2,7 +2,7 @@ use super::super::{get_collection, get_db}; use crate::rocket::futures::StreamExt; use log::info; -use mongodb::bson::{doc, from_bson, Bson}; +use mongodb::bson::{Bson, doc, from_bson, from_document}; use mongodb::options::FindOptions; use serde::{Deserialize, Serialize}; @@ -23,7 +23,7 @@ pub async fn migrate_database() { if let Some(doc) = data { let info: MigrationInfo = - from_bson(Bson::Document(doc)).expect("Failed to read migration information."); + from_document(doc).expect("Failed to read migration information."); let revision = run_migrations(info.revision).await; diff --git a/src/notifications/payload.rs b/src/notifications/payload.rs index 100a521f12f41b9927e9078c880a59bf2ae46a41..7ec7629b303719eb7f6ac3d407895ee2325b90c3 100644 --- a/src/notifications/payload.rs +++ b/src/notifications/payload.rs @@ -4,7 +4,7 @@ use crate::{ util::result::{Error, Result}, }; use futures::StreamExt; -use mongodb::{bson::{Bson, doc, from_bson}, options::FindOptions}; +use mongodb::{bson::{Bson, doc, from_bson, from_document}, options::FindOptions}; use super::websocket::is_online; @@ -37,8 +37,8 @@ pub async fn generate_ready(mut user: User) -> Result<ClientboundNotification> { while let Some(result) = cursor.next().await { if let Ok(doc) = result { let mut user: User = - from_bson(Bson::Document(doc)).map_err(|_| Error::DatabaseError { - operation: "from_bson", + from_document(doc).map_err(|_| Error::DatabaseError { + operation: "from_document", with: "user", })?; @@ -89,9 +89,9 @@ pub async fn generate_ready(mut user: User) -> Result<ClientboundNotification> { while let Some(result) = cursor.next().await { if let Ok(doc) = result { channels.push( - from_bson(Bson::Document(doc)) + from_document(doc) .map_err(|_| Error::DatabaseError { - operation: "from_bson", + operation: "from_document", with: "channel", })? ); diff --git a/src/routes/channels/message_fetch.rs b/src/routes/channels/message_fetch.rs new file mode 100644 index 0000000000000000000000000000000000000000..2c005fde161f42343f0f10741b6546de376c724d --- /dev/null +++ b/src/routes/channels/message_fetch.rs @@ -0,0 +1,67 @@ +use crate::database::*; +use crate::util::result::{Error, Result}; + +use futures::StreamExt; +use validator::Validate; +use rocket::request::Form; +use serde::{Serialize, Deserialize}; +use rocket_contrib::json::JsonValue; +use mongodb::{bson::{doc, from_document}, options::FindOptions}; + +#[derive(Validate, Serialize, Deserialize, FromForm)] +pub struct Options { + #[validate(range(min = 1, max = 100))] + limit: Option<i64>, + #[validate(length(min = 26, max = 26))] + before: Option<String>, + #[validate(length(min = 26, max = 26))] + after: Option<String>, +} + +#[get("/<target>/messages?<options..>")] +pub async fn req(user: User, target: Ref, options: Form<Options>) -> Result<JsonValue> { + options.validate() + .map_err(|error| Error::FailedValidation { error })?; + + let target = target.fetch_channel().await?; + + let perm = permissions::channel::calculate(&user, &target).await; + if !perm.get_view() { + Err(Error::LabelMe)? + } + + let mut query = doc! { "channel": target.id() }; + + if let Some(before) = &options.before { + query.insert("_id", doc! { "$lt": before }); + } + + if let Some(after) = &options.after { + query.insert("_id", doc! { "$gt": after }); + } + + let mut cursor = get_collection("messages") + .find( + query, + FindOptions::builder() + .limit(options.limit.unwrap_or(50)) + .sort(doc! { + "_id": -1 + }) + .build(), + ) + .await + .map_err(|_| Error::DatabaseError { operation: "find", with: "messages" })?; + + let mut messages = vec![]; + while let Some(result) = cursor.next().await { + if let Ok(doc) = result { + messages.push( + from_document::<Message>(doc) + .map_err(|_| Error::DatabaseError { operation: "from_document", with: "message" })? + ); + } + } + + Ok(json!(messages)) +} diff --git a/src/routes/channels/mod.rs b/src/routes/channels/mod.rs index 1b7135e96def0548023fd2ceacdba7e370fa03d4..394250560afc9896b93a70db2ebb5e43e71d8b65 100644 --- a/src/routes/channels/mod.rs +++ b/src/routes/channels/mod.rs @@ -3,11 +3,13 @@ use rocket::Route; mod fetch_channel; mod delete_channel; mod message_send; +mod message_fetch; pub fn routes() -> Vec<Route> { routes![ fetch_channel::req, delete_channel::req, - message_send::req + message_send::req, + message_fetch::req ] }