use std::collections::BTreeMap;
use crate::transport::BoxFuture;
pub type ConnectionKind = &'static str;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SelectOption {
pub id: String,
pub label: String,
pub description: Option<String>,
}
impl SelectOption {
pub fn new(id: impl Into<String>, label: impl Into<String>) -> Self {
SelectOption {
id: id.into(),
label: label.into(),
description: None,
}
}
pub fn described(
id: impl Into<String>,
label: impl Into<String>,
description: Option<String>,
) -> Self {
SelectOption {
id: id.into(),
label: label.into(),
description,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MethodField {
pub id: String,
pub label: String,
pub kind: &'static str,
pub required: bool,
pub options: Vec<SelectOption>,
pub help: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LoginMethod {
pub id: String,
pub label: String,
pub kind: ConnectionKind,
pub flow: &'static str,
pub availability: &'static str,
pub reason: Option<String>,
pub fields: Vec<MethodField>,
pub delivery: Vec<&'static str>,
pub subscription: bool,
pub billing_note: Option<String>,
pub guidance: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProviderDescriptor {
pub id: String,
pub label: String,
pub service: String,
pub routes: Vec<String>,
pub methods: Vec<LoginMethod>,
pub console_url: Option<String>,
}
impl ProviderDescriptor {
pub fn method(&self, id: &str) -> Option<&LoginMethod> {
self.methods.iter().find(|m| m.id == id)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Connection {
pub id: String,
pub provider: String,
pub instance_id: String,
pub kind: String,
pub method_id: String,
pub routes: Vec<String>,
pub label: String,
pub created_at: String,
pub identity_generation: String,
pub credential_revision: String,
pub settings: BTreeMap<String, String>,
pub account_label: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Verification {
pub result: String,
pub checked_at: Option<String>,
pub check: Option<String>,
pub detail: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConnectionStatus {
pub provider: String,
pub presence: &'static str,
pub usability: &'static str,
pub connection: Option<Connection>,
pub expires_at: Option<String>,
pub logged_out: bool,
pub verification: Option<Verification>,
pub detail: Option<String>,
}
impl ConnectionStatus {
pub fn ready(&self) -> bool {
matches!(self.usability, "ready" | "renewal_due")
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ForgetResult {
pub provider: String,
pub forgot: bool,
pub routes: Vec<String>,
pub identity_generation: String,
}
#[derive(Clone, PartialEq, Eq)]
pub struct RequestAuth {
pub credential: Option<(&'static str, String)>,
pub headers: BTreeMap<String, String>,
pub base_url: Option<String>,
pub account_id: Option<String>,
pub named: Option<String>,
}
impl std::fmt::Debug for RequestAuth {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RequestAuth")
.field(
"credential",
&self.credential.as_ref().map(|(kind, _)| *kind),
)
.field("headers", &self.headers.keys().collect::<Vec<_>>())
.field("base_url", &self.base_url)
.field("account_id", &self.account_id)
.field("named", &self.named)
.finish()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Prompt {
Text {
field_id: String,
label: String,
placeholder: Option<String>,
},
Secret {
field_id: String,
label: String,
},
Select {
field_id: String,
label: String,
options: Vec<SelectOption>,
},
ManualCode {
field_id: String,
label: String,
accepted: String,
},
}
impl Prompt {
pub fn kind(&self) -> &'static str {
match self {
Prompt::Text { .. } => "text",
Prompt::Secret { .. } => "secret",
Prompt::Select { .. } => "select",
Prompt::ManualCode { .. } => "manual_code",
}
}
pub fn field_id(&self) -> &str {
match self {
Prompt::Text { field_id, .. }
| Prompt::Secret { field_id, .. }
| Prompt::Select { field_id, .. }
| Prompt::ManualCode { field_id, .. } => field_id,
}
}
pub(crate) fn text(field_id: &str, label: &str) -> Prompt {
Prompt::Text {
field_id: field_id.into(),
label: label.into(),
placeholder: None,
}
}
pub(crate) fn select(field_id: &str, label: &str, options: Vec<SelectOption>) -> Prompt {
Prompt::Select {
field_id: field_id.into(),
label: label.into(),
options,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Notice {
AuthUrl {
url: String,
instructions: String,
},
DeviceCode {
user_code: String,
verification_url: String,
expires_in_s: f64,
interval_s: f64,
},
Progress {
stage: String,
message: String,
},
Info {
message: String,
links: Vec<(String, String)>,
},
}
impl Notice {
pub(crate) fn info(message: impl Into<String>) -> Notice {
Notice::Info {
message: message.into(),
links: Vec::new(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PromptCancelled;
pub trait AuthUi: Send + Sync {
fn prompt<'a>(
&'a self,
prompt: &'a Prompt,
cancel: &'a crate::login::Cancel,
) -> BoxFuture<'a, Result<String, PromptCancelled>>;
fn notify(&self, notice: &Notice);
fn dismiss(&self, _prompt: &Prompt) {}
}