From c6ba72d924bb0012f909fb242151cbbba560caab Mon Sep 17 00:00:00 2001 From: Paul Makles <paulmakles@gmail.com> Date: Mon, 18 Jan 2021 20:07:42 +0000 Subject: [PATCH] Add message sending. --- src/routes/channels/message_send.rs | 57 +++++++++++++++++++++++++++++ src/routes/channels/mod.rs | 4 +- src/util/result.rs | 6 +++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/routes/channels/message_send.rs diff --git a/src/routes/channels/message_send.rs b/src/routes/channels/message_send.rs new file mode 100644 index 0000000..472112d --- /dev/null +++ b/src/routes/channels/message_send.rs @@ -0,0 +1,57 @@ +use crate::database::*; +use crate::util::result::{Error, Result}; + +use serde::{Serialize, Deserialize}; +use rocket_contrib::json::Json; +use validator::Validate; +use mongodb::bson::doc; +use ulid::Ulid; + +#[derive(Validate, Serialize, Deserialize)] +pub struct Data { + #[validate(length(min = 1, max = 2000))] + content: String, + // Maximum length of 36 allows both ULIDs and UUIDs. + #[validate(length(min = 1, max = 36))] + nonce: String, +} + +#[post("/<target>/messages", data = "<message>")] +pub async fn req(user: User, target: Ref, message: Json<Data>) -> Result<()> { + message.validate() + .map_err(|error| Error::FailedValidation { error })?; + + let target = target.fetch_channel().await?; + + let perm = permissions::channel::calculate(&user, &target).await; + if !perm.get_send_message() { + Err(Error::LabelMe)? + } + + if get_collection("messages") + .find_one( + doc! { + "nonce": &message.nonce + }, + None + ) + .await + .map_err(|_| Error::DatabaseError { operation: "find_one", with: "message" })? + .is_some() { + Err(Error::AlreadySentMessage)? + } + + Message { + id: Ulid::new().to_string(), + channel: target.id().to_string(), + author: user.id, + + content: message.content.clone(), + nonce: Some(message.nonce.clone()), + edited: None, + } + .send() + .await?; + + Ok(()) +} diff --git a/src/routes/channels/mod.rs b/src/routes/channels/mod.rs index 2f2d3b9..1b7135e 100644 --- a/src/routes/channels/mod.rs +++ b/src/routes/channels/mod.rs @@ -2,10 +2,12 @@ use rocket::Route; mod fetch_channel; mod delete_channel; +mod message_send; pub fn routes() -> Vec<Route> { routes![ fetch_channel::req, - delete_channel::req + delete_channel::req, + message_send::req ] } diff --git a/src/util/result.rs b/src/util/result.rs index e707f60..2afc546 100644 --- a/src/util/result.rs +++ b/src/util/result.rs @@ -31,6 +31,10 @@ pub enum Error { #[snafu(display("You have been blocked by this user."))] BlockedByOther, + // ? Channel related errors. + #[snafu(display("Already sent a message with this nonce."))] + AlreadySentMessage, + // ? General errors. #[snafu(display("Failed to validate fields."))] FailedValidation { error: ValidationErrors }, @@ -62,6 +66,8 @@ impl<'r> Responder<'r, 'static> for Error { Error::Blocked => Status::Conflict, Error::BlockedByOther => Status::Forbidden, + Error::AlreadySentMessage => Status::Conflict, + Error::FailedValidation { .. } => Status::UnprocessableEntity, Error::DatabaseError { .. } => Status::InternalServerError, Error::InternalError => Status::InternalServerError, -- GitLab