diff --git a/src/client_server/mod.rs b/src/client_server/mod.rs
index e0c340f..115ddaf 100644
--- a/src/client_server/mod.rs
+++ b/src/client_server/mod.rs
@@ -16,6 +16,7 @@ mod profile;
mod push;
mod read_marker;
mod redact;
+mod report;
mod room;
mod search;
mod session;
@@ -47,6 +48,7 @@ pub use profile::*;
pub use push::*;
pub use read_marker::*;
pub use redact::*;
+pub use report::*;
pub use room::*;
pub use search::*;
pub use session::*;
diff --git a/src/client_server/report.rs b/src/client_server/report.rs
new file mode 100644
index 0000000..3dcb4d1
--- /dev/null
+++ b/src/client_server/report.rs
@@ -0,0 +1,83 @@
+use crate::{database::admin::AdminCommand, database::DatabaseGuard, ConduitResult, Error, Ruma};
+use ruma::{
+ api::client::{error::ErrorKind, r0::room::report_content},
+ events::room::message,
+ Int,
+};
+
+#[cfg(feature = "conduit_bin")]
+use rocket::{http::RawStr, post};
+
+/// # `POST /_matrix/client/r0/rooms/{roomId}/report/{eventId}`
+///
+/// Reports an inappropriate event to homeserver admins
+///
+#[cfg_attr(
+ feature = "conduit_bin",
+ post("/_matrix/client/r0/rooms/<_>/report/<_>", data = "
")
+)]
+#[tracing::instrument(skip(db, body))]
+pub async fn report_event_route(
+ db: DatabaseGuard,
+ body: Ruma>,
+) -> ConduitResult {
+ let sender_user = body.sender_user.as_ref().expect("user is authenticated");
+
+ let pdu = match db.rooms.get_pdu(&body.event_id)? {
+ Some(pdu) => pdu,
+ _ => {
+ return Err(Error::BadRequest(
+ ErrorKind::InvalidParam,
+ "Invalid Event ID",
+ ))
+ }
+ };
+
+ if body.score > Int::from(0) || body.score < Int::from(-100) {
+ return Err(Error::BadRequest(
+ ErrorKind::InvalidParam,
+ "Invalid score, must be within 0 to -100",
+ ));
+ };
+
+ if body.reason.chars().count() > 250 {
+ return Err(Error::BadRequest(
+ ErrorKind::InvalidParam,
+ "Reason too long, should be 250 characters or fewer",
+ ));
+ };
+
+ db.admin.send(AdminCommand::SendMessage(
+ message::RoomMessageEventContent::text_html(
+ format!(
+ "Report received from: {}\n\n\
+ Event ID: {}\n\
+ Room ID: {}\n\
+ Sent By: {}\n\n\
+ Report Score: {}\n\
+ Report Reason: {}",
+ sender_user, pdu.event_id, pdu.room_id, pdu.sender, body.score, body.reason
+ )
+ .to_owned(),
+ format!(
+ "Report received from: {0}\
+
- Event Info
- Event ID:
{1}
\
+ 🔗 - Room ID:
{2}
\
+ - Sent By: {3}
- \
+ Report Info
- Report Score: {4}
- Report Reason: {5}
\
+
",
+ sender_user,
+ pdu.event_id,
+ pdu.room_id,
+ pdu.sender,
+ body.score,
+ RawStr::new(&body.reason).html_escape()
+ )
+ .to_owned(),
+ ),
+ ));
+
+ db.flush()?;
+
+ Ok(report_content::Response {}.into())
+}
diff --git a/src/main.rs b/src/main.rs
index 84dfb1f..56faa3e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -101,6 +101,7 @@ fn setup_rocket(config: Figment, data: Arc>) -> rocket::Rocket<
client_server::create_typing_event_route,
client_server::create_room_route,
client_server::redact_event_route,
+ client_server::report_event_route,
client_server::create_alias_route,
client_server::delete_alias_route,
client_server::get_alias_route,