implement API key deletion
This commit is contained in:
parent
bef9cc4cca
commit
588bf33d6e
2 changed files with 113 additions and 3 deletions
|
@ -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<AppState> {
|
|||
.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<Settings>,
|
||||
DbConn(db_conn): DbConn,
|
||||
Path(team_id): Path<Uuid>,
|
||||
CurrentUser(current_user): CurrentUser,
|
||||
Form(form): Form<RemoveApiKeyForm>,
|
||||
) -> Result<impl IntoResponse, AppError> {
|
||||
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<usize, AppError>>(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<Settings>,
|
||||
State(navbar_template): State<NavbarBuilder>,
|
||||
|
|
|
@ -98,7 +98,66 @@
|
|||
>
|
||||
Copy
|
||||
</button>
|
||||
<button class="btn btn-outline-light" type="button">Delete</button>
|
||||
<button
|
||||
class="btn btn-outline-light"
|
||||
type="button"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#confirm-delete-key-modal-{{ key.id }}"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="modal fade"
|
||||
id="confirm-delete-key-modal-{{ key.id }}"
|
||||
tabindex="-1"
|
||||
aria-labelledby="confirm-delete-key-label-{{ key.id }}"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1
|
||||
class="modal-title fs-5"
|
||||
id="confirm-delete-key-label-{{ key.id }}"
|
||||
>
|
||||
Confirm
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Cancel"
|
||||
></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
Are you sure you want to delete the key
|
||||
<code>{{ key.id|compact_uuid|redact }}</code>?
|
||||
{% if let Some(last_used_at) = key.last_used_at %}
|
||||
It was last used: {{ last_used_at.format("%Y-%m-%d") }}.
|
||||
{% else %}
|
||||
It has never been used.
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<form
|
||||
method="post"
|
||||
action="{{ breadcrumbs.join("../remove-api-key") }}"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<input type="hidden" name="key_id" value="{{ key.id }}">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
data-bs-dismiss="modal"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit" class="btn btn-danger">Delete</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
Loading…
Add table
Reference in a new issue