diff options
Diffstat (limited to 'server/src/main.rs')
| -rw-r--r-- | server/src/main.rs | 109 |
1 files changed, 66 insertions, 43 deletions
diff --git a/server/src/main.rs b/server/src/main.rs index d70c4e7..d0547c1 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -5,10 +5,10 @@ use futures::{future::TryFutureExt, stream::TryStreamExt}; use rocket::fairing::{self, AdHoc}; use rocket::figment::Figment; use rocket::http::Status; -use rocket::response::status::{Conflict, Custom, NotFound}; +use rocket::response::status::{Custom, NotFound}; use rocket::serde::json::Json; -use rocket::{futures, Build, Rocket}; -use rocket_db_pools::{sqlx, Connection, Database}; +use rocket::{futures, Build, Rocket, State}; +use rocket_db_pools::{sqlx, Connection, Database, Pool}; use sqlx::Acquire; use std::path::PathBuf; use utoipa::OpenApi; @@ -20,6 +20,10 @@ mod tests; mod api_model; mod auth; mod db_utils; +mod fs_utils; +mod git; +mod git_root; +mod git_socket; use auth::AuthApiAddon; @@ -68,20 +72,6 @@ impl From<api_model::UserReviewRole> for u8 { } } -impl TryFrom<u8> for api_model::ReviewState { - type Error = &'static str; - - fn try_from(value: u8) -> Result<Self, Self::Error> { - match value { - 0 => Ok(api_model::ReviewState::Draft), - 1 => Ok(api_model::ReviewState::Open), - 2 => Ok(api_model::ReviewState::Dropped), - 3 => Ok(api_model::ReviewState::Closed), - _ => Err("Invalid review state"), - } - } -} - #[utoipa::path( responses( (status = 200, description = "Get all projects", body = api_model::Projects), @@ -132,13 +122,13 @@ async fn projects( } async fn get_project( - db: &mut Connection<Db>, + db: &mut <<Db as Database>::Pool as Pool>::Connection, projectid: &str, ) -> Result<Json<api_model::Project>, NotFound<&'static str>> { let users = sqlx::query!( "SELECT id, name, dn, default_role, maintainer FROM users JOIN project_users ON project_users.user=users.id WHERE project_users.project=?", projectid) - .fetch(&mut ***db) + .fetch(&mut **db) .map_ok(|r| api_model::ProjectUserEntry { user: api_model::User { id: r.id, @@ -156,7 +146,7 @@ async fn get_project( "SELECT id,title,description,remote,main_branch FROM projects WHERE id=?", projectid ) - .fetch_one(&mut ***db) + .fetch_one(&mut **db) .map_ok(|r| api_model::Project { id: r.id, title: r.title, @@ -182,11 +172,12 @@ async fn get_project( )] #[get("/project/<projectid>")] async fn project( - mut db: Connection<Db>, + db: &Db, _session: auth::Session, projectid: &str, ) -> Result<Json<api_model::Project>, NotFound<&'static str>> { - get_project(&mut db, projectid).await + let mut conn = db.get().await.unwrap(); + get_project(&mut conn, projectid).await } #[utoipa::path( @@ -200,24 +191,30 @@ async fn project( )] #[post("/project/<projectid>/new", data = "<data>")] async fn project_new( - mut db: Connection<Db>, + db: &Db, + git_roots_config: &State<git_root::Config<'_>>, + roots_state: &State<git_root::Roots>, session: auth::Session, projectid: &str, data: Json<api_model::ProjectData<'_>>, -) -> Result<Json<api_model::Project>, Conflict<&'static str>> { +) -> Result<Json<api_model::Project>, Custom<String>> { + let remote = data.remote.unwrap_or(""); + let main_branch = data.main_branch.unwrap_or("main"); + + let mut conn = db.get().await.unwrap(); { - let mut tx = db.begin().await.unwrap(); + let mut tx = conn.begin().await.unwrap(); sqlx::query!( "INSERT INTO projects (id, title, description, remote, main_branch) VALUES (?, ?, ?, ?, ?)", projectid, data.title.unwrap_or("Unnamed"), data.description.unwrap_or(""), - data.remote.unwrap_or(""), - data.main_branch.unwrap_or("main"), + remote, + main_branch, ) .execute(&mut *tx) - .map_err(|_| Conflict("Project with id already exists")) + .map_err(|_| Custom(Status::Conflict, "Project with id already exists".to_string())) .await?; sqlx::query!( @@ -230,7 +227,12 @@ async fn project_new( tx.commit().await.unwrap(); } - Ok(get_project(&mut db, projectid).await.unwrap()) + roots_state + .new_project(git_roots_config, db, projectid, remote, main_branch) + .map_err(|e| Custom(Status::InternalServerError, e.message)) + .await?; + + Ok(get_project(&mut conn, projectid).await.unwrap()) } async fn project_check_maintainer( @@ -504,25 +506,14 @@ async fn reviews( })) } -#[utoipa::path( - responses( - (status = 200, description = "Get review", body = api_model::Review), - (status = 404, description = "No such review"), - ), - security( - ("session" = []), - ), -)] -#[get("/review/<projectid>/<branch..>")] -async fn review( +async fn get_review_from_branch( mut db: Connection<Db>, - _session: auth::Session, projectid: &str, - branch: PathBuf, + branch: &str, ) -> Result<Json<api_model::Review>, NotFound<&'static str>> { let mut review = sqlx::query!( "SELECT reviews.id AS id,title,description,state,progress,branch,archived,users.id AS user_id,users.name AS name,users.dn AS user_dn FROM reviews JOIN users ON users.id=owner WHERE project=? AND branch=?", - projectid, branch.as_path().to_str().unwrap()) + projectid, branch) .fetch_one(&mut **db) .map_ok(|r| { api_model::Review { @@ -594,6 +585,36 @@ async fn review( #[utoipa::path( responses( + (status = 200, description = "Get review", body = api_model::Review), + (status = 404, description = "No such review"), + ), + security( + ("session" = []), + ), +)] +#[get("/review/<projectid>/<branch..>")] +async fn review( + db: Connection<Db>, + _session: auth::Session, + projectid: &str, + branch: PathBuf, +) -> Result<Json<api_model::Review>, NotFound<&'static str>> { + get_review_from_branch(db, projectid, branch.as_path().to_str().unwrap()).await +} + +// Backup for the above. Matches if <branch> ends up encoded (with / as %2f) +#[get("/review/<projectid>/<branch>", rank = 1)] +async fn review_encoded_path( + db: Connection<Db>, + _session: auth::Session, + projectid: &str, + branch: &str, +) -> Result<Json<api_model::Review>, NotFound<&'static str>> { + get_review_from_branch(db, projectid, branch).await +} + +#[utoipa::path( + responses( (status = 200, description = "Get all users", body = api_model::Users), ), security( @@ -672,10 +693,12 @@ fn rocket_from_config(figment: Figment) -> Rocket<Build> { project_user_del, reviews, review, + review_encoded_path, users, ], ) .attach(auth::stage(basepath)) + .attach(git_root::stage()) } #[rocket::main] |
