015f300941651035945b5cdd98aeada97e4337aa / frogue / src / views / ssh_keys.rs
Raw
use actix_web::HttpResponse;
use maud::{Markup, Render, html};
use super::{
Page,
components::{Complaint, DeleteForm, TextArea},
};
/// A key as the list of them shows it.
pub struct SshKeySummary {
/// The row's id, which is what deletion addresses.
pub id: i64,
pub name: String,
pub algorithm: String,
pub fingerprint: String,
/// When the key was last used to connect, already formatted.
pub last_used: Option<String>,
}
/// What the add-key form shows when it is (re)rendered.
#[derive(Default)]
pub struct SshKeyForm {
pub key: Option<String>,
pub error: Option<String>,
}
pub(super) struct SshKeysBody<'a> {
owner: &'a str,
keys: &'a [SshKeySummary],
form: &'a SshKeyForm,
}
impl Render for SshKeysBody<'_> {
fn render(&self) -> Markup {
html! {
h2 { "SSH keys" }
p {
"A key here is what lets you fetch from and push to your "
"repositories. Passwords are not accepted over SSH."
}
@if self.keys.is_empty() {
p { "No keys yet." }
} @else {
ul class="ssh-keys" {
@for key in self.keys {
li {
strong { (key.name) }
" "
span class="algorithm" { (key.algorithm) }
code { (key.fingerprint) }
@if let Some(last_used) = &key.last_used {
span class="last-used" { "last used " (last_used) }
} @else {
span class="last-used" { "never used" }
}
(DeleteForm {
action: format!("/~{}/ssh-keys/{}/delete", self.owner, key.id),
form_class: None,
button_class: None,
confirm: None,
})
}
}
}
}
h3 { "Add a key" }
(Complaint(self.form.error.as_deref()))
form method="post" action=(format!("/~{}/ssh-keys", self.owner)) {
(TextArea {
label: Some("Public key"),
name: "key",
rows: 4,
value: self.form.key.as_deref(),
required: true,
})
button type="submit" { "Add" }
}
}
}
}
/// The page listing `owner`'s SSH keys, and the form for adding one.
pub fn ssh_keys(
viewer: Option<&str>,
owner: &str,
keys: &[SshKeySummary],
form: &SshKeyForm,
) -> HttpResponse {
Page {
title: format!("Frogue - {owner}'s SSH keys"),
viewer: viewer.map(str::to_string),
extra_head: None,
body: SshKeysBody { owner, keys, form },
}
.into_response()
}