From a9a5af8cc8bc4573ba91be6ef4bf9c14c43a153c Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Wed, 31 May 2023 13:39:13 +0100 Subject: [PATCH] feat: account strike CRUD API --- clippy.toml | 7 +++- .../src/models/safety_strikes/model.rs | 1 + .../database/src/models/safety_strikes/ops.rs | 3 ++ .../src/models/safety_strikes/ops/mongodb.rs | 5 +++ .../models/safety_strikes/ops/reference.rs | 9 +++++ crates/core/models/src/v0/account_strikes.rs | 6 +++ .../delta/src/routes/safety/delete_strike.rs | 23 +++++++++++ crates/delta/src/routes/safety/edit_strike.rs | 39 +++++++++++++++++++ .../delta/src/routes/safety/fetch_strikes.rs | 28 +++++++++++++ crates/delta/src/routes/safety/mod.rs | 10 ++++- 10 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 crates/delta/src/routes/safety/delete_strike.rs create mode 100644 crates/delta/src/routes/safety/edit_strike.rs create mode 100644 crates/delta/src/routes/safety/fetch_strikes.rs diff --git a/clippy.toml b/clippy.toml index bb3ea02e..f2931377 100644 --- a/clippy.toml +++ b/clippy.toml @@ -2,6 +2,11 @@ disallowed-methods = [ # Shouldn't need to access these directly "revolt_database::models::bots::model::Bot::remove_field", - # Prefer to use Object::delete() + # Prefer to use Object::update() "revolt_database::models::bots::ops::AbstractBots::update_bot", + "revolt_database::models::safety_strikes::ops::AbstractAccountStrikes::update_account_strike", + + # Prefer to use Object::delete() + "revolt_database::models::bots::ops::AbstractBots::delete_bot", + "revolt_database::models::safety_strikes::ops::AbstractAccountStrikes::delete_account_strike", ] diff --git a/crates/core/database/src/models/safety_strikes/model.rs b/crates/core/database/src/models/safety_strikes/model.rs index 09bb3d97..ad0f86fe 100644 --- a/crates/core/database/src/models/safety_strikes/model.rs +++ b/crates/core/database/src/models/safety_strikes/model.rs @@ -17,6 +17,7 @@ auto_derived_partial!( "PartialAccountStrike" ); +#[allow(clippy::disallowed_methods)] impl AccountStrike { /// Update this strike pub async fn update(&mut self, db: &Database, partial: PartialAccountStrike) -> Result<()> { diff --git a/crates/core/database/src/models/safety_strikes/ops.rs b/crates/core/database/src/models/safety_strikes/ops.rs index d0dcb60f..a2cdcec5 100644 --- a/crates/core/database/src/models/safety_strikes/ops.rs +++ b/crates/core/database/src/models/safety_strikes/ops.rs @@ -10,6 +10,9 @@ pub trait AbstractAccountStrikes: Sync + Send { /// Insert new strike into the database async fn insert_account_strike(&self, strike: &AccountStrike) -> Result<()>; + /// Fetch strike by id + async fn fetch_account_strike(&self, id: &str) -> Result; + /// Fetch strikes by user id async fn fetch_account_strikes_by_user(&self, user_id: &str) -> Result>; diff --git a/crates/core/database/src/models/safety_strikes/ops/mongodb.rs b/crates/core/database/src/models/safety_strikes/ops/mongodb.rs index 816b69b2..079bc997 100644 --- a/crates/core/database/src/models/safety_strikes/ops/mongodb.rs +++ b/crates/core/database/src/models/safety_strikes/ops/mongodb.rs @@ -15,6 +15,11 @@ impl AbstractAccountStrikes for MongoDb { query!(self, insert_one, COL, &strike).map(|_| ()) } + /// Fetch strike by id + async fn fetch_account_strike(&self, id: &str) -> Result { + query!(self, find_one_by_id, COL, id)?.ok_or_else(|| create_error!(NotFound)) + } + /// Fetch strikes by user id async fn fetch_account_strikes_by_user(&self, user_id: &str) -> Result> { Ok(self diff --git a/crates/core/database/src/models/safety_strikes/ops/reference.rs b/crates/core/database/src/models/safety_strikes/ops/reference.rs index 8ec00a60..aaf8d3d0 100644 --- a/crates/core/database/src/models/safety_strikes/ops/reference.rs +++ b/crates/core/database/src/models/safety_strikes/ops/reference.rs @@ -18,6 +18,15 @@ impl AbstractAccountStrikes for ReferenceDb { } } + /// Fetch strike by id + async fn fetch_account_strike(&self, id: &str) -> Result { + let strikes = self.account_strikes.lock().await; + strikes + .get(id) + .cloned() + .ok_or_else(|| create_error!(NotFound)) + } + /// Fetch strikes by user id async fn fetch_account_strikes_by_user(&self, user_id: &str) -> Result> { let strikes = self.account_strikes.lock().await; diff --git a/crates/core/models/src/v0/account_strikes.rs b/crates/core/models/src/v0/account_strikes.rs index 8bfe01c8..d958fe79 100644 --- a/crates/core/models/src/v0/account_strikes.rs +++ b/crates/core/models/src/v0/account_strikes.rs @@ -10,6 +10,12 @@ auto_derived!( /// Attached reason pub reason: String, } + + /// # Strike Data + pub struct DataEditAccountStrike { + /// New attached reason + pub reason: String, + } ); #[cfg(feature = "from_database")] diff --git a/crates/delta/src/routes/safety/delete_strike.rs b/crates/delta/src/routes/safety/delete_strike.rs new file mode 100644 index 00000000..d11a80e7 --- /dev/null +++ b/crates/delta/src/routes/safety/delete_strike.rs @@ -0,0 +1,23 @@ +use revolt_database::Database; +use revolt_quark::models::User; +use revolt_quark::{Error, Result}; +use rocket::State; + +/// # Delete Strike +/// +/// Delete a strike by its ID +#[openapi(tag = "User Safety")] +#[delete("/strikes/")] +pub async fn delete_strike(db: &State, user: User, strike_id: String) -> Result<()> { + // Must be privileged for this route + if !user.privileged { + return Err(Error::NotPrivileged); + } + + let strike = db + .fetch_account_strike(&strike_id) + .await + .map_err(Error::from_core)?; + + strike.delete(db).await.map_err(Error::from_core) +} diff --git a/crates/delta/src/routes/safety/edit_strike.rs b/crates/delta/src/routes/safety/edit_strike.rs new file mode 100644 index 00000000..81744d11 --- /dev/null +++ b/crates/delta/src/routes/safety/edit_strike.rs @@ -0,0 +1,39 @@ +use revolt_database::{Database, PartialAccountStrike}; +use revolt_models::v0::DataEditAccountStrike; +use revolt_quark::models::User; +use revolt_quark::{Error, Result}; +use rocket::serde::json::Json; +use rocket::State; + +/// # Edit Strike +/// +/// Edit a strike by its ID +#[openapi(tag = "User Safety")] +#[post("/strikes/", data = "")] +pub async fn edit_strike( + db: &State, + user: User, + strike_id: String, + data: Json, +) -> Result<()> { + // Must be privileged for this route + if !user.privileged { + return Err(Error::NotPrivileged); + } + + let mut strike = db + .fetch_account_strike(&strike_id) + .await + .map_err(Error::from_core)?; + + strike + .update( + db, + PartialAccountStrike { + reason: Some(data.0.reason), + ..Default::default() + }, + ) + .await + .map_err(Error::from_core) +} diff --git a/crates/delta/src/routes/safety/fetch_strikes.rs b/crates/delta/src/routes/safety/fetch_strikes.rs new file mode 100644 index 00000000..2ae0b581 --- /dev/null +++ b/crates/delta/src/routes/safety/fetch_strikes.rs @@ -0,0 +1,28 @@ +use revolt_database::Database; +use revolt_models::v0::AccountStrike; +use revolt_quark::models::User; +use revolt_quark::{Error, Result}; +use rocket::serde::json::Json; +use rocket::State; + +/// # Fetch Strikes +/// +/// Fetch strikes for a user by their ID +#[openapi(tag = "User Safety")] +#[get("/strikes/")] +pub async fn fetch_strikes( + db: &State, + user: User, + user_id: String, +) -> Result>> { + // Must be privileged for this route + if !user.privileged { + return Err(Error::NotPrivileged); + } + + db.fetch_account_strikes_by_user(&user_id) + .await + .map(|v| v.into_iter().map(|e| e.into()).collect()) + .map(Json) + .map_err(Error::from_core) +} diff --git a/crates/delta/src/routes/safety/mod.rs b/crates/delta/src/routes/safety/mod.rs index 7487fef4..fac79499 100644 --- a/crates/delta/src/routes/safety/mod.rs +++ b/crates/delta/src/routes/safety/mod.rs @@ -8,6 +8,10 @@ mod report_content; mod fetch_snapshots; +mod delete_strike; +mod edit_strike; +mod fetch_strikes; + pub fn routes() -> (Vec, OpenApi) { openapi_get_routes_spec![ // Reports @@ -16,6 +20,10 @@ pub fn routes() -> (Vec, OpenApi) { fetch_reports::fetch_reports, report_content::report_content, // Snapshots - fetch_snapshots::fetch_snapshots + fetch_snapshots::fetch_snapshots, + // Strikes + fetch_strikes::fetch_strikes, + edit_strike::edit_strike, + delete_strike::delete_strike ] }