From 304336d905087ce303ba3202fd3ac5510dd3572e Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Wed, 1 Mar 2023 11:22:22 +0000 Subject: [PATCH] feat(safety): fetch reports and fetch snapshot API --- .../delta/src/routes/safety/fetch_reports.rs | 17 +++++++++++++++++ .../delta/src/routes/safety/fetch_snapshot.rs | 17 +++++++++++++++++ crates/delta/src/routes/safety/mod.rs | 8 +++++++- .../delta/src/routes/safety/report_content.rs | 3 ++- crates/quark/src/impl/dummy/safety/report.rs | 4 ++++ crates/quark/src/impl/dummy/safety/snapshot.rs | 4 ++++ crates/quark/src/impl/mongo/safety/report.rs | 4 ++++ crates/quark/src/impl/mongo/safety/snapshot.rs | 10 ++++++++++ crates/quark/src/models/safety/report.rs | 18 ++++++++++++++++++ crates/quark/src/models/safety/snapshot.rs | 4 ++-- crates/quark/src/traits/safety/report.rs | 3 +++ crates/quark/src/traits/safety/snapshot.rs | 3 +++ crates/quark/src/util/result.rs | 2 ++ 13 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 crates/delta/src/routes/safety/fetch_reports.rs create mode 100644 crates/delta/src/routes/safety/fetch_snapshot.rs diff --git a/crates/delta/src/routes/safety/fetch_reports.rs b/crates/delta/src/routes/safety/fetch_reports.rs new file mode 100644 index 00000000..5b418472 --- /dev/null +++ b/crates/delta/src/routes/safety/fetch_reports.rs @@ -0,0 +1,17 @@ +use revolt_quark::models::{Report, User}; +use revolt_quark::{Db, Error, Result}; +use rocket::serde::json::Json; + +/// # Fetch Reports +/// +/// Fetch all available reports +#[openapi(tag = "User Safety")] +#[get("/reports")] +pub async fn fetch_reports(db: &Db, user: User) -> Result>> { + // Must be privileged for this route + if !user.privileged { + return Err(Error::NotPrivileged); + } + + db.fetch_reports().await.map(Json) +} diff --git a/crates/delta/src/routes/safety/fetch_snapshot.rs b/crates/delta/src/routes/safety/fetch_snapshot.rs new file mode 100644 index 00000000..2b46d5e9 --- /dev/null +++ b/crates/delta/src/routes/safety/fetch_snapshot.rs @@ -0,0 +1,17 @@ +use revolt_quark::models::{Snapshot, User}; +use revolt_quark::{Db, Error, Result}; +use rocket::serde::json::Json; + +/// # Fetch Snapshot +/// +/// Fetch a snapshot for a given report +#[openapi(tag = "User Safety")] +#[get("/snapshot/")] +pub async fn fetch_snapshot(db: &Db, user: User, report_id: String) -> Result> { + // Must be privileged for this route + if !user.privileged { + return Err(Error::NotPrivileged); + } + + db.fetch_snapshot(&report_id).await.map(Json) +} diff --git a/crates/delta/src/routes/safety/mod.rs b/crates/delta/src/routes/safety/mod.rs index 29102aa6..30214530 100644 --- a/crates/delta/src/routes/safety/mod.rs +++ b/crates/delta/src/routes/safety/mod.rs @@ -1,11 +1,17 @@ use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi; use rocket::Route; +mod fetch_reports; mod report_content; +mod fetch_snapshot; + pub fn routes() -> (Vec, OpenApi) { openapi_get_routes_spec![ // Reports - report_content::report_content + report_content::report_content, + fetch_reports::fetch_reports, + // Snapshots + fetch_snapshot::fetch_snapshot ] } diff --git a/crates/delta/src/routes/safety/report_content.rs b/crates/delta/src/routes/safety/report_content.rs index 295b4e2b..8b0da822 100644 --- a/crates/delta/src/routes/safety/report_content.rs +++ b/crates/delta/src/routes/safety/report_content.rs @@ -1,5 +1,5 @@ use revolt_quark::events::client::EventV1; -use revolt_quark::models::report::ReportedContent; +use revolt_quark::models::report::{ReportStatus, ReportedContent}; use revolt_quark::models::snapshot::{Snapshot, SnapshotContent}; use revolt_quark::models::{Report, User}; use revolt_quark::{Db, Error, Result}; @@ -149,6 +149,7 @@ pub async fn report_content(db: &Db, user: User, data: Json) author_id: user.id, content: data.content, additional_context: data.additional_context, + status: ReportStatus::Created, }; db.insert_report(&report).await?; diff --git a/crates/quark/src/impl/dummy/safety/report.rs b/crates/quark/src/impl/dummy/safety/report.rs index 5286976c..c1f80886 100644 --- a/crates/quark/src/impl/dummy/safety/report.rs +++ b/crates/quark/src/impl/dummy/safety/report.rs @@ -9,4 +9,8 @@ impl AbstractReport for DummyDb { info!("Insert {:?}", report); Ok(()) } + + async fn fetch_reports(&self) -> Result> { + Ok(vec![]) + } } diff --git a/crates/quark/src/impl/dummy/safety/snapshot.rs b/crates/quark/src/impl/dummy/safety/snapshot.rs index 8d384059..a99447dd 100644 --- a/crates/quark/src/impl/dummy/safety/snapshot.rs +++ b/crates/quark/src/impl/dummy/safety/snapshot.rs @@ -9,4 +9,8 @@ impl AbstractSnapshot for DummyDb { info!("Insert {:?}", snapshot); Ok(()) } + + async fn fetch_snapshot(&self, _report_id: &str) -> Result { + todo!() + } } diff --git a/crates/quark/src/impl/mongo/safety/report.rs b/crates/quark/src/impl/mongo/safety/report.rs index 6b364d11..da0a84c4 100644 --- a/crates/quark/src/impl/mongo/safety/report.rs +++ b/crates/quark/src/impl/mongo/safety/report.rs @@ -10,4 +10,8 @@ impl AbstractReport for MongoDb { async fn insert_report(&self, report: &Report) -> Result<()> { self.insert_one(COL, report).await.map(|_| ()) } + + async fn fetch_reports(&self) -> Result> { + self.find(COL, doc! {}).await + } } diff --git a/crates/quark/src/impl/mongo/safety/snapshot.rs b/crates/quark/src/impl/mongo/safety/snapshot.rs index d4dd29f6..6b31de9f 100644 --- a/crates/quark/src/impl/mongo/safety/snapshot.rs +++ b/crates/quark/src/impl/mongo/safety/snapshot.rs @@ -10,4 +10,14 @@ impl AbstractSnapshot for MongoDb { async fn insert_snapshot(&self, snapshot: &Snapshot) -> Result<()> { self.insert_one(COL, snapshot).await.map(|_| ()) } + + async fn fetch_snapshot(&self, report_id: &str) -> Result { + self.find_one( + COL, + doc! { + "report_id": report_id + }, + ) + .await + } } diff --git a/crates/quark/src/models/safety/report.rs b/crates/quark/src/models/safety/report.rs index db4552e8..66098da0 100644 --- a/crates/quark/src/models/safety/report.rs +++ b/crates/quark/src/models/safety/report.rs @@ -44,6 +44,7 @@ pub enum UserReportReason { Underage, } +/// The content being reported #[derive(Serialize, Deserialize, JsonSchema, Debug, Clone)] #[serde(tag = "type")] pub enum ReportedContent { @@ -70,6 +71,20 @@ pub enum ReportedContent { }, } +/// Status of the report +#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone)] +#[serde(tag = "status")] +pub enum ReportStatus { + /// Report is waiting for triage / action + Created, + + /// Report was rejected + Rejected { rejection_reason: String }, + + /// Report was actioned and resolved + Resolved, +} + /// User-generated platform moderation report. #[derive(Serialize, Deserialize, JsonSchema, Debug, Clone)] pub struct Report { @@ -82,4 +97,7 @@ pub struct Report { pub content: ReportedContent, /// Additional report context pub additional_context: String, + /// Status of the report + #[serde(flatten)] + pub status: ReportStatus, } diff --git a/crates/quark/src/models/safety/snapshot.rs b/crates/quark/src/models/safety/snapshot.rs index f9674de8..e1d28df1 100644 --- a/crates/quark/src/models/safety/snapshot.rs +++ b/crates/quark/src/models/safety/snapshot.rs @@ -9,11 +9,11 @@ use crate::models::{Message, Server, User}; pub enum SnapshotContent { Message { /// Context before the message - #[serde(rename = "_prior_context")] + #[serde(rename = "_prior_context", default)] prior_context: Vec, /// Context after the message - #[serde(rename = "_leading_context")] + #[serde(rename = "_leading_context", default)] leading_context: Vec, /// Message diff --git a/crates/quark/src/traits/safety/report.rs b/crates/quark/src/traits/safety/report.rs index f5a15e39..0fa3766c 100644 --- a/crates/quark/src/traits/safety/report.rs +++ b/crates/quark/src/traits/safety/report.rs @@ -5,4 +5,7 @@ use crate::Result; pub trait AbstractReport: Sync + Send { /// Insert a new report into the database async fn insert_report(&self, report: &Report) -> Result<()>; + + /// Fetch reports + async fn fetch_reports(&self) -> Result>; } diff --git a/crates/quark/src/traits/safety/snapshot.rs b/crates/quark/src/traits/safety/snapshot.rs index 9f6ac84e..2c1e4d9c 100644 --- a/crates/quark/src/traits/safety/snapshot.rs +++ b/crates/quark/src/traits/safety/snapshot.rs @@ -5,4 +5,7 @@ use crate::Result; pub trait AbstractSnapshot: Sync + Send { /// Insert a new snapshot into the database async fn insert_snapshot(&self, snapshot: &Snapshot) -> Result<()>; + + /// Fetch a snapshot by a report's id + async fn fetch_snapshot(&self, report_id: &str) -> Result; } diff --git a/crates/quark/src/util/result.rs b/crates/quark/src/util/result.rs index 6efbd01f..66613527 100644 --- a/crates/quark/src/util/result.rs +++ b/crates/quark/src/util/result.rs @@ -75,6 +75,7 @@ pub enum Error { permission: UserPermission, }, NotElevated, + NotPrivileged, CannotGiveMissingPermissions, NotOwner, @@ -174,6 +175,7 @@ impl<'r> Responder<'r, 'static> for Error { Error::MissingPermission { .. } => Status::Forbidden, Error::MissingUserPermission { .. } => Status::Forbidden, Error::NotElevated => Status::Forbidden, + Error::NotPrivileged => Status::Forbidden, Error::CannotGiveMissingPermissions => Status::Forbidden, Error::NotOwner => Status::Forbidden,