summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSanto Cariotti <santo@dcariotti.me>2022-09-26 21:04:23 +0000
committerSanto Cariotti <santo@dcariotti.me>2022-09-26 21:04:23 +0000
commit484dd4c1c6bed35ff2ad315c1546eebfd5e9f428 (patch)
tree8e411701a382093b354663c3a1304015707c16d0 /src
parent9a3713339f7f38db7249ba4086d0622a1a9c3896 (diff)
Edit warning
Diffstat (limited to 'src')
-rw-r--r--src/models/warning.rs105
-rw-r--r--src/routes/warning.rs33
2 files changed, 118 insertions, 20 deletions
diff --git a/src/models/warning.rs b/src/models/warning.rs
index 68c2773..2cb051d 100644
--- a/src/models/warning.rs
+++ b/src/models/warning.rs
@@ -3,34 +3,51 @@ use chrono::{Local, NaiveDateTime};
use serde::{Deserialize, Serialize};
use sqlx::types::JsonValue;
use sqlx::Row;
+use std::convert::From;
/// Model for warnings.
#[derive(Deserialize, Serialize, sqlx::FromRow)]
pub struct Warning {
- id: i32,
- user_id: Option<i32>,
- model_id: Option<i32>,
- resolved_by: Option<i32>,
- note: String,
- admin_note: String,
- created: NaiveDateTime,
- updated: NaiveDateTime,
+ pub id: i32,
+ pub user_id: Option<i32>,
+ pub model_id: Option<i32>,
+ pub resolved_by: Option<i32>,
+ pub note: String,
+ pub admin_note: String,
+ pub created: NaiveDateTime,
+ pub updated: NaiveDateTime,
}
#[derive(Serialize, sqlx::FromRow)]
pub struct WarningUser {
- id: i32,
- user_id: Option<i32>,
- model_id: Option<i32>,
- resolved_by: Option<i32>,
- note: String,
- admin_note: String,
- created: NaiveDateTime,
- updated: NaiveDateTime,
+ pub id: i32,
+ pub user_id: Option<i32>,
+ pub model_id: Option<i32>,
+ pub resolved_by: Option<i32>,
+ pub note: String,
+ pub admin_note: String,
+ pub created: NaiveDateTime,
+ pub updated: NaiveDateTime,
user: Option<JsonValue>,
resolved: Option<JsonValue>,
}
+/// Impl conversion from `WarningUser` to `Warning`
+impl From<WarningUser> for Warning {
+ fn from(item: WarningUser) -> Self {
+ Self {
+ id: item.id,
+ user_id: item.user_id,
+ model_id: item.model_id,
+ resolved_by: item.resolved_by,
+ note: item.note,
+ admin_note: item.admin_note,
+ created: item.created,
+ updated: item.created,
+ }
+ }
+}
+
/// Payload used to create a new warning
#[derive(Deserialize)]
pub struct WarningCreate {
@@ -38,6 +55,12 @@ pub struct WarningCreate {
pub note: String,
}
+/// Payload used to edit a warning
+#[derive(Deserialize)]
+pub struct WarningEdit {
+ pub admin_note: String,
+}
+
/// Payload used for warning filtering
#[derive(Deserialize)]
pub struct WarningFilterPayload {
@@ -107,6 +130,31 @@ impl Warning {
Ok(rows)
}
+ /// Returns the warning with id = `warning_id`
+ pub async fn find_by_id(warning_id: i32) -> Result<WarningUser, AppError> {
+ let pool = unsafe { get_client() };
+
+ let rec: WarningUser = sqlx::query_as(
+ r#"
+ SELECT
+ warnings.*,
+ json_build_object('id', users.id, 'name', users.name, 'email', users.email, 'username', users.username, 'is_staff', users.is_staff, 'avatar', users.avatar) as user,
+ coalesce(r.data, '{}'::json) as resolved
+ FROM warnings
+ JOIN users ON users.id = warnings.user_id
+ LEFT JOIN (
+ SELECT id, json_build_object('id', r.id, 'name', r.name, 'email', r.email, 'username', r.username, 'is_staff', r.is_staff, 'avatar', r.avatar) as data
+ FROM users r
+ ) r ON r.id = warnings.resolved_by
+ WHERE warnings.id = $1
+ "#)
+ .bind(warning_id)
+ .fetch_one(pool)
+ .await?;
+
+ Ok(rec)
+ }
+
/// Return the number of warnings.
pub async fn count(user_id: Option<i32>) -> Result<i64, AppError> {
let pool = unsafe { get_client() };
@@ -221,4 +269,29 @@ impl Warning {
let count: i64 = cursor.try_get(0).unwrap();
Ok(count)
}
+
+ /// Edit a warning
+ pub async fn edit(&mut self, resolver: i32, payload: WarningEdit) -> Result<(), AppError> {
+ let pool = unsafe { get_client() };
+
+ let now = Local::now().naive_utc();
+
+ sqlx::query(
+ r#"
+ UPDATE warnings SET admin_note = $1, resolved_by = $2, updated = $3 WHERE id = $4
+ "#,
+ )
+ .bind(&payload.admin_note)
+ .bind(resolver)
+ .bind(now)
+ .bind(self.id)
+ .execute(pool)
+ .await?;
+
+ self.admin_note = payload.admin_note;
+ self.resolved_by = Some(resolver);
+ self.updated = now;
+
+ Ok(())
+ }
}
diff --git a/src/routes/warning.rs b/src/routes/warning.rs
index 3a8573e..bb1306e 100644
--- a/src/routes/warning.rs
+++ b/src/routes/warning.rs
@@ -4,14 +4,14 @@ use crate::{
auth::Claims,
model::Model,
user::User,
- warning::{Warning, WarningCreate, WarningFilter, WarningFilterPayload},
+ warning::{Warning, WarningCreate, WarningEdit, WarningFilter, WarningFilterPayload},
},
pagination::{Pagination, WarningPagination},
routes::JsonCreate,
};
use axum::{
- extract::Query,
- routing::{get, post},
+ extract::{Path, Query},
+ routing::{get, post, put},
Json, Router,
};
@@ -19,6 +19,7 @@ use axum::{
pub fn create_route() -> Router {
Router::new()
.route("/", get(list_warnings).post(create_warning))
+ .route("/:id", put(edit_warning))
.route("/filter", post(filter_warnings))
}
@@ -52,7 +53,7 @@ async fn create_warning(
) -> Result<JsonCreate<Warning>, AppError> {
let model = match Model::find_by_id(payload.model_id).await {
Ok(model) => model,
- Err(_) => return Err(AppError::NotFound("Model not found".to_string())),
+ Err(_) => return Err(AppError::NotFound("Report not found".to_string())),
};
let warning = Warning::new(claims.user_id, model.id, payload.note);
@@ -62,6 +63,30 @@ async fn create_warning(
Ok(JsonCreate(warning_new))
}
+/// Staffers can edit a warning
+async fn edit_warning(
+ Json(payload): Json<WarningEdit>,
+ claims: Claims,
+ Path(warning_id): Path<i32>,
+) -> Result<Json<Warning>, AppError> {
+ let mut warning: Warning = match Warning::find_by_id(warning_id).await {
+ Ok(warning) => warning.into(),
+ Err(_) => {
+ return Err(AppError::NotFound("Report not found".to_string()));
+ }
+ };
+
+ let user = User::find_by_id(claims.user_id).await?;
+
+ if !(user.is_staff.unwrap()) {
+ return Err(AppError::Unauthorized);
+ }
+
+ warning.edit(user.id, payload).await?;
+
+ Ok(Json(warning))
+}
+
/// Apply a filter to warnings list
async fn filter_warnings(
Json(payload): Json<WarningFilterPayload>,