feat: add validation to project creation and update endpoints
Some checks failed
ci/woodpecker/push/check_fmt Pipeline failed

This commit is contained in:
Mika Bomm 2025-04-03 10:40:59 +02:00
parent f20802682a
commit 8e460ec6dd
6 changed files with 48 additions and 25 deletions

View file

@ -13,4 +13,7 @@ REDIS_PORT=
SECRET_KEY=
# LDAP section
LDAP_ADMIN_PASSWORD=
LDAP_ADMIN_PASSWORD=
# Rust log level
RUST_LOG=info

View file

@ -20,6 +20,7 @@ env_logger = "0.11"
log = "0.4"
serde = { version = "1", features = ["derive"] }
validator = { version = "0.20.0", features = ["derive"] }
sea-orm = { version = "1.1", features = [
"sqlx-postgres",
"runtime-tokio-rustls",

View file

@ -1,18 +1,13 @@
use std::path;
use actix_web::{Result, delete, get, post, put, web};
use sea_orm::prelude::Uuid;
use serde::Deserialize;
use crate::dto::project::UpdateProject;
use validator::Validate;
use crate::db::Database;
use crate::db::project::CreateProject;
use crate::error::ApiError;
// Maybe move this here into the corresponding DTO file
#[derive(Deserialize)]
struct CreateProject {
name: String,
}
pub fn setup(cfg: &mut actix_web::web::ServiceConfig) {
cfg.service(get_project)
.service(get_projects)
@ -45,20 +40,22 @@ async fn get_project(
#[post("")]
async fn create_project(
db: web::Data<Database>,
create_project_struct: web::Json<CreateProject>,
create_project: web::Json<CreateProject>,
) -> Result<web::Json<entity::project::Model>, ApiError> {
let result = db.create_project(&create_project_struct.name).await?;
create_project.validate()?;
let result = db.create_project(create_project.into_inner()).await?;
Ok(web::Json(result))
}
#[put("")]
#[put("/{id}")]
async fn update_project(
db: web::Data<Database>,
update_project_struct: web::Json<UpdateProject>,
path: web::Path<Uuid>,
update_project: web::Json<CreateProject>,
) -> Result<web::Json<entity::project::Model>, ApiError> {
let updated_project = db
.update_project(update_project_struct.into_inner())
.update_project(&path, update_project.into_inner())
.await?;
Ok(web::Json(updated_project))

View file

@ -1,7 +1,7 @@
use sea_orm::{ConnectOptions, DatabaseConnection};
mod group;
mod project;
pub mod project;
mod user;
#[derive(Clone)]

View file

@ -2,12 +2,18 @@ use super::Database;
use crate::error::ApiError;
use log::debug;
use crate::dto::project::UpdateProject;
use entity::project;
use sea_orm::ActiveValue::{NotSet, Set, Unchanged};
use sea_orm::prelude::Uuid;
use sea_orm::{ActiveModelTrait, DeleteResult, EntityTrait};
use serde::Deserialize;
use validator::Validate;
#[derive(Deserialize, Validate)]
pub struct CreateProject {
#[validate(length(min = 3))]
name: String,
}
impl Database {
pub async fn get_projects(&self) -> Result<Vec<project::Model>, ApiError> {
@ -30,23 +36,30 @@ impl Database {
Ok(project)
}
pub async fn create_project(&self, name: &str) -> Result<project::Model, ApiError> {
debug!("Creating project with name: {}", name);
pub async fn create_project(
&self,
create_project: CreateProject,
) -> Result<project::Model, ApiError> {
debug!("Creating project with name: {}", create_project.name);
let project = project::ActiveModel {
id: NotSet,
name: Set(name.to_owned()),
name: Set(create_project.name),
};
let project = project.insert(&self.conn).await?;
Ok(project)
}
pub async fn update_project(&self, project: UpdateProject) -> Result<project::Model, ApiError> {
debug!("Updating project with id: {}", &project.id);
pub async fn update_project(
&self,
id: &Uuid,
project: CreateProject,
) -> Result<project::Model, ApiError> {
debug!("Updating project with id: {}", &id);
let active_model = project::ActiveModel {
id: Unchanged(project.id),
id: Unchanged(*id),
name: Set(project.name),
};

View file

@ -1,12 +1,18 @@
use actix_web::{HttpResponse, ResponseError, http::StatusCode};
use actix_web::{HttpResponse, ResponseError, cookie::time::error, http::StatusCode};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ApiError {
#[error("Database Error: {0}")]
Database(#[from] sea_orm::DbErr),
#[error("Unauthorized")]
Unauthorized,
#[error("Not Found")]
NotFound,
#[error("Bad Request: {0}")]
BadRequest(String),
#[error("Validation Error: {0}")]
ValidationError(#[from] validator::ValidationErrors),
}
impl ResponseError for ApiError {
@ -14,6 +20,9 @@ impl ResponseError for ApiError {
match self {
ApiError::Database(..) => StatusCode::INTERNAL_SERVER_ERROR,
ApiError::NotFound => StatusCode::NOT_FOUND,
ApiError::Unauthorized => StatusCode::UNAUTHORIZED,
ApiError::BadRequest(..) => StatusCode::BAD_REQUEST,
ApiError::ValidationError(..) => StatusCode::BAD_REQUEST,
}
}