Create Project APIs.
This commit is contained in:
parent
d8094c4812
commit
d4b8302306
9 changed files with 250 additions and 6 deletions
106
backend/src/services/projects.rs
Normal file
106
backend/src/services/projects.rs
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
use axum::{
|
||||
Json, Router,
|
||||
extract::{Path, State},
|
||||
http::StatusCode,
|
||||
routing::{get, post},
|
||||
};
|
||||
use axum_extra::extract::WithRejection;
|
||||
use serde::Deserialize;
|
||||
use sqlx::{Pool, Sqlite};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::models::{ProjectModel, ProjectStatus};
|
||||
|
||||
use super::AppError;
|
||||
|
||||
pub fn create_project_router() -> Router<Pool<Sqlite>> {
|
||||
Router::new()
|
||||
.route("/", post(create_project).get(list_projects))
|
||||
.route(
|
||||
"/{project_id}",
|
||||
get(get_project).put(update_project).delete(delete_project),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct CreateProjectRequest {
|
||||
title: String,
|
||||
color: String,
|
||||
}
|
||||
|
||||
pub async fn create_project(
|
||||
State(pool): State<Pool<Sqlite>>,
|
||||
WithRejection(Json(input), _): WithRejection<Json<CreateProjectRequest>, AppError>,
|
||||
) -> Result<(StatusCode, Json<ProjectModel>), AppError> {
|
||||
Ok((
|
||||
StatusCode::CREATED,
|
||||
Json(ProjectModel::insert(&pool, input.title, input.color).await?),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn list_projects(
|
||||
State(pool): State<Pool<Sqlite>>,
|
||||
) -> Result<(StatusCode, Json<Vec<ProjectModel>>), AppError> {
|
||||
Ok((StatusCode::OK, Json(ProjectModel::list(&pool).await?)))
|
||||
}
|
||||
|
||||
pub async fn get_project(
|
||||
State(pool): State<Pool<Sqlite>>,
|
||||
WithRejection(Path(project_id), _): WithRejection<Path<Uuid>, AppError>,
|
||||
) -> Result<(StatusCode, Json<ProjectModel>), AppError> {
|
||||
Ok((
|
||||
StatusCode::OK,
|
||||
Json(ProjectModel::get_by_id(&pool, project_id).await?),
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct UpdateProjectRequest {
|
||||
title: Option<String>,
|
||||
color: Option<String>,
|
||||
status: Option<ProjectStatus>,
|
||||
}
|
||||
|
||||
pub async fn update_project(
|
||||
State(pool): State<Pool<Sqlite>>,
|
||||
WithRejection(Path(project_id), _): WithRejection<Path<Uuid>, AppError>,
|
||||
WithRejection(Json(input), _): WithRejection<Json<UpdateProjectRequest>, AppError>,
|
||||
) -> Result<(StatusCode, Json<ProjectModel>), AppError> {
|
||||
let mut project = ProjectModel::get_by_id(&pool, project_id).await?;
|
||||
|
||||
if let Some(new_title) = input.title {
|
||||
if new_title.len() == 0 {
|
||||
return Err(AppError::Unprocessable(
|
||||
"Title must not be empty".to_string(),
|
||||
));
|
||||
}
|
||||
project.title = new_title;
|
||||
}
|
||||
|
||||
if let Some(color) = input.color {
|
||||
if color.len() != 7 || color.chars().next() != Some('#') {
|
||||
return Err(AppError::Unprocessable(
|
||||
"Color is not a valid hex".to_string(),
|
||||
));
|
||||
}
|
||||
project.color = color;
|
||||
}
|
||||
|
||||
if let Some(status) = input.status {
|
||||
project.status = status;
|
||||
}
|
||||
|
||||
Ok((StatusCode::OK, Json(project.update(&pool).await?)))
|
||||
}
|
||||
|
||||
pub async fn delete_project(
|
||||
State(pool): State<Pool<Sqlite>>,
|
||||
WithRejection(Path(project_id), _): WithRejection<Path<Uuid>, AppError>,
|
||||
) -> Result<StatusCode, AppError> {
|
||||
ProjectModel::get_by_id(&pool, project_id).await?;
|
||||
ProjectModel::delete(&pool, project_id).await?;
|
||||
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue