From c93e35b21655d23477b59d187854e337ee17fd43 Mon Sep 17 00:00:00 2001 From: Ash Svitan Date: Wed, 8 Jul 2026 19:30:41 +0200 Subject: [PATCH] :sparkles: Adds action CRUD --- backend/src/api/action.rs | 105 ++++++++++++++++++++++++++++++++++- backend/src/dtos/action.rs | 17 +++++- backend/src/main.rs | 11 +++- backend/src/models/action.rs | 4 +- backend/src/models/mod.rs | 2 +- 5 files changed, 133 insertions(+), 6 deletions(-) diff --git a/backend/src/api/action.rs b/backend/src/api/action.rs index 9b841c3..050f8c4 100644 --- a/backend/src/api/action.rs +++ b/backend/src/api/action.rs @@ -1,5 +1,5 @@ use crate::auth::Authenticated; -use crate::dtos::action::ActionDTO; +use crate::dtos::action::{ActionDTO, NewActionDTO, UpdateActionDTO}; use crate::models::action::Action; use crate::models::{AppState, DEFAULT_QUERY_LIMIT}; use crate::schema::actions::dsl::actions; @@ -7,6 +7,7 @@ use diesel::{QueryDsl, RunQueryDsl, SelectableHelper}; use rocket::State; use rocket::http::Status; use rocket::serde::json::Json; +use uuid::Uuid; #[get("/?&")] pub fn index( @@ -32,3 +33,105 @@ pub fn index( None => Err(Status::InternalServerError), } } + +#[put("/", format = "json", data = "")] +pub fn create( + data: Json, + _auth: Authenticated, + state: &State, +) -> Result, Status> { + let mut db = state.db.get().unwrap(); + + let new = Action { + id: Uuid::new_v4(), + name: data.name.clone(), + source: data.source.clone(), + created_at: chrono::Local::now().naive_local(), + updated_at: chrono::Local::now().naive_local(), + }; + + let result = diesel::insert_into(actions) + .values(&new) + .returning(Action::as_returning()) + .get_result(&mut db) + .ok(); + + match result { + Some(result) => Ok(Json(ActionDTO::from(&result))), + None => Err(Status::InternalServerError), + } +} + +// TODO: add execute +#[get("/")] +pub fn get( + id: &str, + _auth: Authenticated, + state: &State, +) -> Result, Status> { + let mut db = state.db.get().unwrap(); + + let id = match Uuid::parse_str(id).ok() { + Some(id) => id, + None => return Err(Status::BadRequest), + }; + + let result = actions.find(id).first(&mut db).ok(); + + match result { + Some(result) => Ok(Json(ActionDTO::from(&result))), + None => Err(Status::NotFound), + } +} + +#[patch("/", format = "json", data = "")] +pub fn update( + id: &str, + data: Json, + _auth: Authenticated, + state: &State, +) -> Result { + let mut db = state.db.get().unwrap(); + + let id = match Uuid::parse_str(id).ok() { + Some(id) => id, + None => return Err(Status::BadRequest), + }; + + let rows = diesel::update(actions.find(id)) + .set(&*data) + .execute(&mut db) + .ok(); + + match rows { + Some(rows) => { + if rows == 0 { + return Err(Status::NotFound); + } + Ok(Status::NoContent) + } + None => Err(Status::InternalServerError), + } +} + +#[delete("/")] +pub fn delete(id: &str, _auth: Authenticated, state: &State) -> Result { + let mut db = state.db.get().unwrap(); + + let id = match Uuid::parse_str(id).ok() { + Some(id) => id, + None => return Err(Status::BadRequest), + }; + + let rows = diesel::delete(actions.find(id)).execute(&mut db).ok(); + + match rows { + Some(rows) => { + if rows == 0 { + return Err(Status::NotFound); + } + Ok(Status::NoContent) + } + None => Err(Status::InternalServerError), + } +} diff --git a/backend/src/dtos/action.rs b/backend/src/dtos/action.rs index d0041d7..0238619 100644 --- a/backend/src/dtos/action.rs +++ b/backend/src/dtos/action.rs @@ -1,5 +1,7 @@ use crate::models::action::Action; -use serde::Serialize; +use crate::schema::actions; +use diesel::AsChangeset; +use serde::{Deserialize, Serialize}; #[derive(Serialize)] pub struct ActionDTO { @@ -21,3 +23,16 @@ impl ActionDTO { } } } + +#[derive(Deserialize)] +pub struct NewActionDTO { + pub name: String, + pub source: String, +} + +#[derive(Deserialize, AsChangeset)] +#[diesel(table_name = actions)] +pub struct UpdateActionDTO { + pub name: Option, + pub source: Option, +} diff --git a/backend/src/main.rs b/backend/src/main.rs index ef37107..4ccfece 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -67,5 +67,14 @@ fn rocket() -> _ { .manage(app_data) .attach(CORS {}) .mount("/", routes![index]) - .mount("/action", routes![action::index]) + .mount( + "/action", + routes![ + action::index, + action::create, + action::get, + action::update, + action::delete + ], + ) } diff --git a/backend/src/models/action.rs b/backend/src/models/action.rs index 51a7904..7379aee 100644 --- a/backend/src/models/action.rs +++ b/backend/src/models/action.rs @@ -1,8 +1,8 @@ use chrono::NaiveDateTime; -use diesel::{Queryable, Selectable}; +use diesel::{Insertable, Queryable, Selectable}; use uuid::Uuid; -#[derive(Queryable, Selectable)] +#[derive(Queryable, Selectable, Insertable)] #[diesel(table_name = crate::schema::actions)] #[diesel(check_for_backend(diesel::pg::Pg))] pub struct Action { diff --git a/backend/src/models/mod.rs b/backend/src/models/mod.rs index f67694a..105f8e0 100644 --- a/backend/src/models/mod.rs +++ b/backend/src/models/mod.rs @@ -1,5 +1,5 @@ -use diesel::r2d2::{ConnectionManager, Pool}; use diesel::PgConnection; +use diesel::r2d2::{ConnectionManager, Pool}; pub const DEFAULT_QUERY_LIMIT: i64 = 100;