summaryrefslogtreecommitdiff
path: root/server/src/main.rs
diff options
context:
space:
mode:
authorJoel Klinghed <the_jk@spawned.biz>2025-01-09 21:52:34 +0100
committerJoel Klinghed <the_jk@spawned.biz>2025-01-09 22:07:54 +0100
commitf7d3d4a1ea50f3d2abad76cb809e43e6d8636bb7 (patch)
treed893df15f91a6d1897c71550f30f78e9246ceb45 /server/src/main.rs
parent3747204267e8b75bc77d6c0962b67bbe018dad15 (diff)
Improve (and test) error handling
Non existent projects, users and such.
Diffstat (limited to 'server/src/main.rs')
-rw-r--r--server/src/main.rs51
1 files changed, 37 insertions, 14 deletions
diff --git a/server/src/main.rs b/server/src/main.rs
index e48cfb7..d70c4e7 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -5,7 +5,7 @@ use futures::{future::TryFutureExt, stream::TryStreamExt};
use rocket::fairing::{self, AdHoc};
use rocket::figment::Figment;
use rocket::http::Status;
-use rocket::response::status::{Custom, NotFound};
+use rocket::response::status::{Conflict, Custom, NotFound};
use rocket::serde::json::Json;
use rocket::{futures, Build, Rocket};
use rocket_db_pools::{sqlx, Connection, Database};
@@ -192,6 +192,7 @@ async fn project(
#[utoipa::path(
responses(
(status = 200, description = "Project created", body = api_model::Project),
+ (status = 409, description = "Project with id already exists"),
),
security(
("session" = []),
@@ -203,7 +204,7 @@ async fn project_new(
session: auth::Session,
projectid: &str,
data: Json<api_model::ProjectData<'_>>,
-) -> Json<api_model::Project> {
+) -> Result<Json<api_model::Project>, Conflict<&'static str>> {
{
let mut tx = db.begin().await.unwrap();
@@ -216,8 +217,8 @@ async fn project_new(
data.main_branch.unwrap_or("main"),
)
.execute(&mut *tx)
- .await
- .unwrap();
+ .map_err(|_| Conflict("Project with id already exists"))
+ .await?;
sqlx::query!(
"INSERT INTO project_users (project, user, default_role, maintainer) VALUES (?, ?, ?, ?)",
@@ -229,7 +230,7 @@ async fn project_new(
tx.commit().await.unwrap();
}
- get_project(&mut db, projectid).await.unwrap()
+ Ok(get_project(&mut db, projectid).await.unwrap())
}
async fn project_check_maintainer(
@@ -310,6 +311,7 @@ async fn project_update(
(status = 200, description = "User added to project"),
(status = 401, description = "Not maintainer of project"),
(status = 404, description = "No such project"),
+ (status = 409, description = "User already in project"),
),
security(
("session" = []),
@@ -336,8 +338,8 @@ async fn project_user_add(
data.maintainer.unwrap_or(false)
)
.execute(&mut **db)
- .await
- .unwrap();
+ .map_err(|_| Custom(Status::Conflict, "User already in project"))
+ .await?;
Ok("")
}
@@ -346,7 +348,7 @@ async fn project_user_add(
responses(
(status = 200, description = "User updated in project"),
(status = 401, description = "Not maintainer of project"),
- (status = 404, description = "No such project"),
+ (status = 404, description = "No such project, no such user or user not in project"),
),
security(
("session" = []),
@@ -383,7 +385,10 @@ async fn project_user_update(
let mut query_builder: sqlx::QueryBuilder<sqlx::MySql> =
sqlx::QueryBuilder::with_arguments(query, args);
- query_builder.build().execute(&mut **db).await.unwrap();
+ let result = query_builder.build().execute(&mut **db).await.unwrap();
+ if result.rows_affected() == 0 {
+ return Err(Custom(Status::NotFound, "No such project or no such user"));
+ }
}
Ok("")
@@ -393,7 +398,7 @@ async fn project_user_update(
responses(
(status = 200, description = "User removed from project"),
(status = 401, description = "Not maintainer of project"),
- (status = 404, description = "No such project"),
+ (status = 404, description = "No such project, no such user or user not in project"),
),
security(
("session" = []),
@@ -412,7 +417,7 @@ async fn project_user_del(
project_check_maintainer(&mut db, session, projectid).await?;
}
- sqlx::query!(
+ let result = sqlx::query!(
"DELETE FROM project_users WHERE project=? AND user=?",
projectid,
userid
@@ -420,6 +425,9 @@ async fn project_user_del(
.execute(&mut **db)
.await
.unwrap();
+ if result.rows_affected() == 0 {
+ return Err(Custom(Status::NotFound, "No such project or no such user"));
+ }
Ok("")
}
@@ -427,6 +435,7 @@ async fn project_user_del(
#[utoipa::path(
responses(
(status = 200, description = "Get all reviews for project", body = api_model::Reviews),
+ (status = 404, description = "No such project"),
),
security(
("session" = []),
@@ -439,7 +448,7 @@ async fn reviews(
projectid: &str,
limit: Option<u32>,
offset: Option<u32>,
-) -> Json<api_model::Reviews> {
+) -> Result<Json<api_model::Reviews>, NotFound<&'static str>> {
let uw_offset = offset.unwrap_or(0);
let uw_limit = limit.unwrap_or(10);
let entries = sqlx::query!(
@@ -470,15 +479,29 @@ async fn reviews(
.await
.unwrap();
+ if count == 0 {
+ let projects = sqlx::query!(
+ "SELECT COUNT(id) AS count FROM projects WHERE id=?",
+ projectid
+ )
+ .fetch_one(&mut **db)
+ .map_ok(|r| r.count)
+ .await
+ .unwrap();
+ if projects == 0 {
+ return Err(NotFound("No such project"));
+ }
+ }
+
let u32_count = u32::try_from(count).unwrap();
- Json(api_model::Reviews {
+ Ok(Json(api_model::Reviews {
offset: uw_offset,
limit: uw_limit,
total_count: u32_count,
more: uw_offset + uw_limit < u32_count,
reviews: entries,
- })
+ }))
}
#[utoipa::path(