summaryrefslogtreecommitdiff
path: root/server/src
diff options
context:
space:
mode:
authorJoel Klinghed <the_jk@spawned.biz>2025-02-06 00:05:57 +0100
committerJoel Klinghed <the_jk@spawned.biz>2025-02-06 00:05:57 +0100
commitbd74717e10fb36e19893c15941876b2383b94714 (patch)
tree5fc26ace64c37fb439ba94cc5ea437a0e93913d2 /server/src
parent350fc534de745f4cc62000fa25d67afcddb7918a (diff)
Add DELETE command for review
Only the owner or a maintainer of the project can remove a review. Removing a review also removes the git branch. Only reviews that are either draft or dropped can be removed.
Diffstat (limited to 'server/src')
-rw-r--r--server/src/git_root.rs14
-rw-r--r--server/src/main.rs176
2 files changed, 190 insertions, 0 deletions
diff --git a/server/src/git_root.rs b/server/src/git_root.rs
index 31e4d45..f818495 100644
--- a/server/src/git_root.rs
+++ b/server/src/git_root.rs
@@ -62,6 +62,20 @@ impl Roots {
Ok(())
}
+
+ pub async fn del_branch(&self, project_id: &str, branch: &str) -> Result<(), git::Error> {
+ let repo;
+ {
+ let data = self.data.lock().unwrap();
+ if let Some(tmp_repo) = data.project_repo.get(project_id) {
+ repo = tmp_repo.clone();
+ } else {
+ return Ok(());
+ }
+ }
+
+ repo.delete_branch(branch).await
+ }
}
#[derive(Debug)]
diff --git a/server/src/main.rs b/server/src/main.rs
index 019f28f..f07c372 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -46,6 +46,8 @@ struct Db(sqlx::MySqlPool);
reviews,
review,
review_id,
+ review_del,
+ review_id_del,
users,
user_key_add,
user_key_get,
@@ -633,6 +635,114 @@ async fn get_review_from_id(
Ok(Json(review))
}
+#[allow(clippy::too_many_arguments)]
+async fn del_review(
+ mut db: Connection<Db>,
+ roots: &State<git_root::Roots>,
+ session: auth::Session,
+ projectid: &str,
+ reviewid: u64,
+ state: u8,
+ owner: &str,
+ branch: &str,
+) -> Result<&'static str, Custom<&'static str>> {
+ let state = api_model::ReviewState::try_from(state).unwrap();
+
+ if owner != session.user_id
+ && project_check_maintainer(&mut db, session, projectid)
+ .await
+ .is_err()
+ {
+ return Err(Custom(
+ Status::Unauthorized,
+ "Not owner of review or maintainer of project",
+ ));
+ }
+
+ match state {
+ api_model::ReviewState::Draft | api_model::ReviewState::Dropped => {}
+ api_model::ReviewState::Open | api_model::ReviewState::Closed => {
+ return Err(Custom(Status::BadRequest, "Review is open or closed"));
+ }
+ }
+
+ roots
+ .del_branch(projectid, branch)
+ .map_err(|_| Custom(Status::InternalServerError, "git error"))
+ .await?;
+
+ sqlx::query!(
+ "DELETE FROM reviews WHERE project=? AND id=?",
+ projectid,
+ reviewid
+ )
+ .execute(&mut **db)
+ .await
+ .unwrap();
+
+ Ok("")
+}
+
+async fn del_review_from_branch(
+ mut db: Connection<Db>,
+ roots: &State<git_root::Roots>,
+ session: auth::Session,
+ projectid: &str,
+ branch: &str,
+) -> Result<&'static str, Custom<&'static str>> {
+ let (id, state, owner) = sqlx::query!(
+ "SELECT id,state,owner FROM reviews WHERE project=? AND branch=?",
+ projectid,
+ branch
+ )
+ .fetch_one(&mut **db)
+ .map_ok(|r| (r.id, r.state, r.owner))
+ .map_err(|_| Custom(Status::NotFound, "No such review"))
+ .await?;
+
+ del_review(
+ db,
+ roots,
+ session,
+ projectid,
+ id,
+ state,
+ owner.as_str(),
+ branch,
+ )
+ .await
+}
+
+async fn del_review_from_id(
+ mut db: Connection<Db>,
+ roots: &State<git_root::Roots>,
+ session: auth::Session,
+ projectid: &str,
+ reviewid: u64,
+) -> Result<&'static str, Custom<&'static str>> {
+ let (state, branch, owner) = sqlx::query!(
+ "SELECT state,branch,owner FROM reviews WHERE project=? AND id=?",
+ projectid,
+ reviewid
+ )
+ .fetch_one(&mut **db)
+ .map_ok(|r| (r.state, r.branch, r.owner))
+ .map_err(|_| Custom(Status::NotFound, "No such review"))
+ .await?;
+
+ del_review(
+ db,
+ roots,
+ session,
+ projectid,
+ reviewid,
+ state,
+ owner.as_str(),
+ branch.as_str(),
+ )
+ .await
+}
+
#[utoipa::path(
responses(
(status = 200, description = "Get review", body = api_model::Review),
@@ -665,6 +775,47 @@ async fn review_encoded_path(
#[utoipa::path(
responses(
+ (status = 200, description = "Review deleted"),
+ (status = 400, description = "Review is open or closed"),
+ (status = 401, description = "Not owner of review or maintainer of project"),
+ (status = 404, description = "No such review"),
+ ),
+ security(
+ ("session" = []),
+ ),
+)]
+#[delete("/review/<projectid>/<branch..>")]
+async fn review_del(
+ db: Connection<Db>,
+ roots: &State<git_root::Roots>,
+ session: auth::Session,
+ projectid: &str,
+ branch: PathBuf,
+) -> Result<&'static str, Custom<&'static str>> {
+ del_review_from_branch(
+ db,
+ roots,
+ session,
+ projectid,
+ branch.as_path().to_str().unwrap(),
+ )
+ .await
+}
+
+// Backup for the above. Matches if <branch> ends up encoded (with / as %2f)
+#[delete("/review/<projectid>/<branch>", rank = 1)]
+async fn review_encoded_path_del(
+ db: Connection<Db>,
+ roots: &State<git_root::Roots>,
+ session: auth::Session,
+ projectid: &str,
+ branch: &str,
+) -> Result<&'static str, Custom<&'static str>> {
+ del_review_from_branch(db, roots, session, projectid, branch).await
+}
+
+#[utoipa::path(
+ responses(
(status = 200, description = "Get review", body = api_model::Review),
(status = 404, description = "No such review"),
),
@@ -684,6 +835,28 @@ async fn review_id(
#[utoipa::path(
responses(
+ (status = 200, description = "Remove deleted"),
+ (status = 400, description = "Review is open or closed"),
+ (status = 401, description = "Not owner of review or maintainer of project"),
+ (status = 404, description = "No such review"),
+ ),
+ security(
+ ("session" = []),
+ ),
+)]
+#[delete("/review/<projectid>?<reviewid>")]
+async fn review_id_del(
+ db: Connection<Db>,
+ roots: &State<git_root::Roots>,
+ session: auth::Session,
+ projectid: &str,
+ reviewid: u64,
+) -> Result<&'static str, Custom<&'static str>> {
+ del_review_from_id(db, roots, session, projectid, reviewid).await
+}
+
+#[utoipa::path(
+ responses(
(status = 200, description = "Get all users", body = api_model::Users),
),
security(
@@ -941,8 +1114,11 @@ fn rocket_from_config(figment: Figment) -> Rocket<Build> {
project_user_del,
reviews,
review,
+ review_del,
review_encoded_path,
+ review_encoded_path_del,
review_id,
+ review_id_del,
users,
user_key_add,
user_key_get,