feat(safety): fetch reports and fetch snapshot API

This commit is contained in:
Paul Makles
2023-03-01 11:22:22 +00:00
parent 42b4906594
commit 304336d905
13 changed files with 93 additions and 4 deletions

View File

@@ -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<Json<Vec<Report>>> {
// Must be privileged for this route
if !user.privileged {
return Err(Error::NotPrivileged);
}
db.fetch_reports().await.map(Json)
}

View File

@@ -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/<report_id>")]
pub async fn fetch_snapshot(db: &Db, user: User, report_id: String) -> Result<Json<Snapshot>> {
// Must be privileged for this route
if !user.privileged {
return Err(Error::NotPrivileged);
}
db.fetch_snapshot(&report_id).await.map(Json)
}

View File

@@ -1,11 +1,17 @@
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi; use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
use rocket::Route; use rocket::Route;
mod fetch_reports;
mod report_content; mod report_content;
mod fetch_snapshot;
pub fn routes() -> (Vec<Route>, OpenApi) { pub fn routes() -> (Vec<Route>, OpenApi) {
openapi_get_routes_spec![ openapi_get_routes_spec![
// Reports // Reports
report_content::report_content report_content::report_content,
fetch_reports::fetch_reports,
// Snapshots
fetch_snapshot::fetch_snapshot
] ]
} }

View File

@@ -1,5 +1,5 @@
use revolt_quark::events::client::EventV1; 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::snapshot::{Snapshot, SnapshotContent};
use revolt_quark::models::{Report, User}; use revolt_quark::models::{Report, User};
use revolt_quark::{Db, Error, Result}; use revolt_quark::{Db, Error, Result};
@@ -149,6 +149,7 @@ pub async fn report_content(db: &Db, user: User, data: Json<DataReportContent>)
author_id: user.id, author_id: user.id,
content: data.content, content: data.content,
additional_context: data.additional_context, additional_context: data.additional_context,
status: ReportStatus::Created,
}; };
db.insert_report(&report).await?; db.insert_report(&report).await?;

View File

@@ -9,4 +9,8 @@ impl AbstractReport for DummyDb {
info!("Insert {:?}", report); info!("Insert {:?}", report);
Ok(()) Ok(())
} }
async fn fetch_reports(&self) -> Result<Vec<Report>> {
Ok(vec![])
}
} }

View File

@@ -9,4 +9,8 @@ impl AbstractSnapshot for DummyDb {
info!("Insert {:?}", snapshot); info!("Insert {:?}", snapshot);
Ok(()) Ok(())
} }
async fn fetch_snapshot(&self, _report_id: &str) -> Result<Snapshot> {
todo!()
}
} }

View File

@@ -10,4 +10,8 @@ impl AbstractReport for MongoDb {
async fn insert_report(&self, report: &Report) -> Result<()> { async fn insert_report(&self, report: &Report) -> Result<()> {
self.insert_one(COL, report).await.map(|_| ()) self.insert_one(COL, report).await.map(|_| ())
} }
async fn fetch_reports(&self) -> Result<Vec<Report>> {
self.find(COL, doc! {}).await
}
} }

View File

@@ -10,4 +10,14 @@ impl AbstractSnapshot for MongoDb {
async fn insert_snapshot(&self, snapshot: &Snapshot) -> Result<()> { async fn insert_snapshot(&self, snapshot: &Snapshot) -> Result<()> {
self.insert_one(COL, snapshot).await.map(|_| ()) self.insert_one(COL, snapshot).await.map(|_| ())
} }
async fn fetch_snapshot(&self, report_id: &str) -> Result<Snapshot> {
self.find_one(
COL,
doc! {
"report_id": report_id
},
)
.await
}
} }

View File

@@ -44,6 +44,7 @@ pub enum UserReportReason {
Underage, Underage,
} }
/// The content being reported
#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone)] #[derive(Serialize, Deserialize, JsonSchema, Debug, Clone)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum ReportedContent { 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. /// User-generated platform moderation report.
#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone)] #[derive(Serialize, Deserialize, JsonSchema, Debug, Clone)]
pub struct Report { pub struct Report {
@@ -82,4 +97,7 @@ pub struct Report {
pub content: ReportedContent, pub content: ReportedContent,
/// Additional report context /// Additional report context
pub additional_context: String, pub additional_context: String,
/// Status of the report
#[serde(flatten)]
pub status: ReportStatus,
} }

View File

@@ -9,11 +9,11 @@ use crate::models::{Message, Server, User};
pub enum SnapshotContent { pub enum SnapshotContent {
Message { Message {
/// Context before the message /// Context before the message
#[serde(rename = "_prior_context")] #[serde(rename = "_prior_context", default)]
prior_context: Vec<Message>, prior_context: Vec<Message>,
/// Context after the message /// Context after the message
#[serde(rename = "_leading_context")] #[serde(rename = "_leading_context", default)]
leading_context: Vec<Message>, leading_context: Vec<Message>,
/// Message /// Message

View File

@@ -5,4 +5,7 @@ use crate::Result;
pub trait AbstractReport: Sync + Send { pub trait AbstractReport: Sync + Send {
/// Insert a new report into the database /// Insert a new report into the database
async fn insert_report(&self, report: &Report) -> Result<()>; async fn insert_report(&self, report: &Report) -> Result<()>;
/// Fetch reports
async fn fetch_reports(&self) -> Result<Vec<Report>>;
} }

View File

@@ -5,4 +5,7 @@ use crate::Result;
pub trait AbstractSnapshot: Sync + Send { pub trait AbstractSnapshot: Sync + Send {
/// Insert a new snapshot into the database /// Insert a new snapshot into the database
async fn insert_snapshot(&self, snapshot: &Snapshot) -> Result<()>; 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<Snapshot>;
} }

View File

@@ -75,6 +75,7 @@ pub enum Error {
permission: UserPermission, permission: UserPermission,
}, },
NotElevated, NotElevated,
NotPrivileged,
CannotGiveMissingPermissions, CannotGiveMissingPermissions,
NotOwner, NotOwner,
@@ -174,6 +175,7 @@ impl<'r> Responder<'r, 'static> for Error {
Error::MissingPermission { .. } => Status::Forbidden, Error::MissingPermission { .. } => Status::Forbidden,
Error::MissingUserPermission { .. } => Status::Forbidden, Error::MissingUserPermission { .. } => Status::Forbidden,
Error::NotElevated => Status::Forbidden, Error::NotElevated => Status::Forbidden,
Error::NotPrivileged => Status::Forbidden,
Error::CannotGiveMissingPermissions => Status::Forbidden, Error::CannotGiveMissingPermissions => Status::Forbidden,
Error::NotOwner => Status::Forbidden, Error::NotOwner => Status::Forbidden,