diff --git a/crates/delta/src/routes/mod.rs b/crates/delta/src/routes/mod.rs index f50ef91f..f700b23a 100644 --- a/crates/delta/src/routes/mod.rs +++ b/crates/delta/src/routes/mod.rs @@ -10,6 +10,7 @@ mod invites; mod onboard; mod push; mod root; +mod safety; mod servers; mod sync; mod users; @@ -27,6 +28,7 @@ pub fn mount(mut rocket: Rocket) -> Rocket { "/servers" => servers::routes(), "/invites" => invites::routes(), "/custom" => customisation::routes(), + "/safety" => safety::routes(), "/auth/account" => rocket_rauth::routes::account::routes(), "/auth/session" => rocket_rauth::routes::session::routes(), "/auth/mfa" => rocket_rauth::routes::mfa::routes(), @@ -105,6 +107,12 @@ fn custom_openapi_spec() -> OpenApi { "Emojis" ] }, + { + "name": "Platform Moderation", + "tags": [ + "User Safety" + ] + }, { "name": "Authentication", "tags": [ diff --git a/crates/delta/src/routes/safety/mod.rs b/crates/delta/src/routes/safety/mod.rs new file mode 100644 index 00000000..fea6c823 --- /dev/null +++ b/crates/delta/src/routes/safety/mod.rs @@ -0,0 +1,11 @@ +use rocket::Route; +use rocket_okapi::okapi::openapi3::OpenApi; + +mod report_content; + +pub fn routes() -> (Vec, OpenApi) { + openapi_get_routes_spec![ + // Reports + report_content::report_content + ] +} diff --git a/crates/delta/src/routes/safety/report_content.rs b/crates/delta/src/routes/safety/report_content.rs new file mode 100644 index 00000000..f6b848c7 --- /dev/null +++ b/crates/delta/src/routes/safety/report_content.rs @@ -0,0 +1,52 @@ +use revolt_quark::models::User; +use revolt_quark::{Db, Error, Result}; +use serde::Deserialize; +use validator::Validate; + +use rocket::serde::json::Json; + +#[derive(Deserialize, JsonSchema)] +enum UserReportReason { + NoneSpecified, + InappropriateProfile, +} + +// TODO: move me into models +#[derive(Deserialize, JsonSchema)] +pub enum ReportedContent { + User { + id: String, + report_reason: UserReportReason, + }, +} + +/// # Report Data +#[derive(Validate, Deserialize, JsonSchema)] +pub struct DataReportContent { + /// Content being reported + content: ReportedContent, + /// Additional report description + #[validate(length(min = 0, max = 1000))] + #[serde(default)] + additional_context: String, +} + +/// # Report Content +/// +/// Report a piece of content to the moderation team. +#[openapi(tag = "User Safety")] +#[post("/report", data = "")] +pub async fn report_content(db: &Db, user: User, data: Json) -> Result<()> { + let data = data.into_inner(); + data.validate() + .map_err(|error| Error::FailedValidation { error })?; + + // Bots cannot create reports + if user.bot.is_some() { + return Err(Error::IsBot); + } + + // find the content and create the report here + + Ok(()) +} diff --git a/crates/quark/src/web/ratelimiter.rs b/crates/quark/src/web/ratelimiter.rs index f7e0dd62..003881cc 100644 --- a/crates/quark/src/web/ratelimiter.rs +++ b/crates/quark/src/web/ratelimiter.rs @@ -126,6 +126,8 @@ fn resolve_bucket<'r>(request: &'r rocket::Request<'_>) -> (&'r str, Option<&'r } } ("swagger", _) => ("swagger", None), + ("safety", Some("report")) => ("safety_report", Some("report")), + ("safety", _) => ("safety", None), _ => ("any", None), } } else { @@ -145,6 +147,8 @@ fn resolve_bucket_limit(bucket: &str) -> u8 { "auth_delete" => 255, "default_avatar" => 255, "swagger" => 100, + "safety" => 15, + "safety_report" => 3, _ => 20, } }