From accd6d7789639d2cf250904e6658d6639c3a5cbf Mon Sep 17 00:00:00 2001 From: Paul Makles <paulmakles@gmail.com> Date: Mon, 18 Jan 2021 20:54:08 +0000 Subject: [PATCH] Add edit message route. --- src/database/entities/message.rs | 20 ++++++++++ src/database/guards/reference.rs | 2 +- src/database/guards/user.rs | 2 +- src/database/migrations/scripts.rs | 2 +- src/notifications/events.rs | 2 + src/notifications/payload.rs | 2 +- src/routes/channels/message_edit.rs | 58 +++++++++++++++++++++++++++++ src/routes/channels/mod.rs | 4 +- src/util/result.rs | 3 ++ 9 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 src/routes/channels/message_edit.rs diff --git a/src/database/entities/message.rs b/src/database/entities/message.rs index 8cec6ce..13975de 100644 --- a/src/database/entities/message.rs +++ b/src/database/entities/message.rs @@ -58,4 +58,24 @@ impl Message { Ok(()) } + + pub async fn publish_edit(self) -> Result<()> { + let channel = self.channel.clone(); + ClientboundNotification::MessageEdit(self) + .publish(channel) + .await + .ok(); + + Ok(()) + } + + pub async fn publish_delete(self) -> Result<()> { + let channel = self.channel.clone(); + ClientboundNotification::MessageDelete(self.id) + .publish(channel) + .await + .ok(); + + Ok(()) + } } diff --git a/src/database/guards/reference.rs b/src/database/guards/reference.rs index a1262c3..829ff24 100644 --- a/src/database/guards/reference.rs +++ b/src/database/guards/reference.rs @@ -1,7 +1,7 @@ use crate::database::*; use crate::util::result::{Error, Result}; -use mongodb::bson::{doc, from_bson, from_document, Bson}; +use mongodb::bson::{doc, from_document}; use rocket::http::RawStr; use rocket::request::FromParam; use serde::{de::DeserializeOwned, Deserialize, Serialize}; diff --git a/src/database/guards/user.rs b/src/database/guards/user.rs index c7363d1..fb8e53d 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, from_document, Bson}; +use mongodb::bson::{doc, from_document}; use rauth::auth::Session; use rocket::http::Status; use rocket::request::{self, FromRequest, Outcome, Request}; diff --git a/src/database/migrations/scripts.rs b/src/database/migrations/scripts.rs index 64866c0..4f57000 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, from_document, Bson}; +use mongodb::bson::{doc, from_document}; use mongodb::options::FindOptions; use serde::{Deserialize, Serialize}; diff --git a/src/notifications/events.rs b/src/notifications/events.rs index eeb03a9..cde3946 100644 --- a/src/notifications/events.rs +++ b/src/notifications/events.rs @@ -37,6 +37,8 @@ pub enum ClientboundNotification { }, Message(Message), + MessageEdit(Message), + MessageDelete(String), /*MessageCreate { id: String, diff --git a/src/notifications/payload.rs b/src/notifications/payload.rs index c3b2559..32ae010 100644 --- a/src/notifications/payload.rs +++ b/src/notifications/payload.rs @@ -5,7 +5,7 @@ use crate::{ }; use futures::StreamExt; use mongodb::{ - bson::{doc, from_bson, from_document, Bson}, + bson::{doc, from_document}, options::FindOptions, }; diff --git a/src/routes/channels/message_edit.rs b/src/routes/channels/message_edit.rs new file mode 100644 index 0000000..ccc2f8a --- /dev/null +++ b/src/routes/channels/message_edit.rs @@ -0,0 +1,58 @@ +use crate::database::*; +use crate::util::result::{Error, Result}; + +use chrono::Utc; +use mongodb::bson::{Bson, DateTime, doc}; +use rocket_contrib::json::Json; +use serde::{Deserialize, Serialize}; +use validator::Validate; + +#[derive(Validate, Serialize, Deserialize)] +pub struct Data { + #[validate(length(min = 1, max = 2000))] + content: String, +} + +#[patch("/<target>/messages/<msg>", data = "<edit>")] +pub async fn req(user: User, target: Ref, msg: Ref, edit: Json<Data>) -> Result<()> { + edit.validate() + .map_err(|error| Error::FailedValidation { error })?; + + let channel = target.fetch_channel().await?; + + let perm = permissions::channel::calculate(&user, &channel).await; + if !perm.get_view() { + Err(Error::LabelMe)? + } + + let mut message = msg.fetch_message().await?; + if message.author != user.id { + Err(Error::CannotEditMessage)? + } + + let edited = Utc::now(); + get_collection("messages") + .update_one( + doc! { + "_id": &message.id + }, + doc! { + "$set": { + "content": &edit.content, + "edited": Bson::DateTime(edited) + } + }, + None, + ) + .await + .map_err(|_| Error::DatabaseError { + operation: "update_one", + with: "message", + })?; + + message.content = edit.content.clone(); + message.edited = Some(DateTime(edited)); + message.publish_edit().await?; + + Ok(()) +} diff --git a/src/routes/channels/mod.rs b/src/routes/channels/mod.rs index fbd9e7d..f888557 100644 --- a/src/routes/channels/mod.rs +++ b/src/routes/channels/mod.rs @@ -2,6 +2,7 @@ use rocket::Route; mod delete_channel; mod fetch_channel; +mod message_edit; mod message_fetch; mod message_query; mod message_send; @@ -12,6 +13,7 @@ pub fn routes() -> Vec<Route> { delete_channel::req, message_send::req, message_query::req, - message_fetch::req + message_fetch::req, + message_edit::req ] } diff --git a/src/util/result.rs b/src/util/result.rs index 2afc546..0f2dec3 100644 --- a/src/util/result.rs +++ b/src/util/result.rs @@ -34,6 +34,8 @@ pub enum Error { // ? Channel related errors. #[snafu(display("Already sent a message with this nonce."))] AlreadySentMessage, + #[snafu(display("Cannot edit someone else's message."))] + CannotEditMessage, // ? General errors. #[snafu(display("Failed to validate fields."))] @@ -67,6 +69,7 @@ impl<'r> Responder<'r, 'static> for Error { Error::BlockedByOther => Status::Forbidden, Error::AlreadySentMessage => Status::Conflict, + Error::CannotEditMessage => Status::Forbidden, Error::FailedValidation { .. } => Status::UnprocessableEntity, Error::DatabaseError { .. } => Status::InternalServerError, -- GitLab