diff --git a/src/teams_router.rs b/src/teams_router.rs index 74feff4..58acfb9 100644 --- a/src/teams_router.rs +++ b/src/teams_router.rs @@ -19,7 +19,7 @@ use crate::{ guards, nav::{BreadcrumbTrail, Navbar, NavbarBuilder, NAVBAR_ITEM_TEAMS}, projects::{Project, DEFAULT_PROJECT_NAME}, - schema::{team_memberships, teams}, + schema::{api_keys, team_memberships, teams}, settings::Settings, team_memberships::TeamMembership, teams::Team, @@ -31,6 +31,7 @@ pub fn new_router() -> Router { .route("/teams", get(teams_page)) .route("/teams/{team_id}", get(team_page)) .route("/teams/{team_id}/new-api-key", post(post_new_api_key)) + .route("/teams/{team_id}/remove-api-key", post(remove_api_key)) .route("/new-team", get(new_team_page)) .route("/new-team", post(post_new_team)) } @@ -96,11 +97,61 @@ async fn post_new_api_key( Ok(Redirect::to(&format!( "{}/en/teams/{}/projects", base_path, - team.id.hyphenated() + team.id.simple() )) .into_response()) } +#[derive(Deserialize)] +struct RemoveApiKeyForm { + csrf_token: String, + key_id: Uuid, +} + +async fn remove_api_key( + State(Settings { base_path, .. }): State, + DbConn(db_conn): DbConn, + Path(team_id): Path, + CurrentUser(current_user): CurrentUser, + Form(form): Form, +) -> Result { + guards::require_valid_csrf_token(&form.csrf_token, ¤t_user, &db_conn).await?; + let team = guards::require_team_membership(¤t_user, &team_id, &db_conn).await?; + + let n_deleted = { + let team_id = team.id; + db_conn + .interact::<_, Result>(move |conn| { + diesel::delete( + api_keys::table + .filter(ApiKey::with_team(&team_id)) + .filter(ApiKey::with_id(&form.key_id)), + ) + .execute(conn) + .context("failed to delete API key from database") + .map_err(Into::into) + }) + .await + .unwrap()? + }; + assert!( + n_deleted < 2, + "there should never be more than 1 API key with the same ID" + ); + if n_deleted == 0 { + Err(AppError::NotFoundError( + "no API key with that ID and team found".to_owned(), + )) + } else { + Ok(Redirect::to(&format!( + "{}/en/teams/{}/projects", + base_path, + team.id.simple() + )) + .into_response()) + } +} + async fn new_team_page( State(Settings { base_path, .. }): State, State(navbar_template): State, diff --git a/templates/projects.html b/templates/projects.html index c1c6ff4..df54acf 100644 --- a/templates/projects.html +++ b/templates/projects.html @@ -98,7 +98,66 @@ > Copy - + + +