use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::messaging_card::ir::MessageCardIr;
use crate::messaging_card::types::{MessageCard, OauthCard, OauthPrompt, OauthProvider};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RenderIntent {
Card,
Auth,
}
#[derive(Debug, Clone, PartialEq)]
pub enum RenderSpec {
Card(Box<MessageCardIr>),
Auth(AuthRenderSpec),
}
impl RenderSpec {
pub fn intent(&self) -> RenderIntent {
match self {
RenderSpec::Card(_) => RenderIntent::Card,
RenderSpec::Auth(_) => RenderIntent::Auth,
}
}
pub fn as_card(&self) -> Option<&MessageCardIr> {
match self {
RenderSpec::Card(ir) => Some(ir.as_ref()),
_ => None,
}
}
pub fn as_auth(&self) -> Option<&AuthRenderSpec> {
match self {
RenderSpec::Auth(spec) => Some(spec),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AuthRenderSpec {
pub provider: OauthProvider,
pub scopes: Vec<String>,
pub resource: Option<String>,
pub prompt: Option<OauthPrompt>,
pub metadata: Option<Value>,
pub start_url: Option<String>,
pub connection_name: Option<String>,
pub fallback_button: FallbackButton,
}
impl AuthRenderSpec {
pub fn from_card(card: &MessageCard, oauth: &OauthCard) -> Self {
let fallback_title = card
.title
.clone()
.unwrap_or_else(|| format!("Sign in with {}", oauth.provider.display_name()));
let fallback_button = FallbackButton {
title: fallback_title,
url: oauth.start_url.clone(),
};
Self {
provider: oauth.provider.clone(),
scopes: oauth.scopes.clone(),
resource: oauth.resource.clone(),
prompt: oauth.prompt.clone(),
metadata: oauth.metadata.clone(),
start_url: oauth.start_url.clone(),
connection_name: oauth.connection_name.clone(),
fallback_button,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FallbackButton {
pub title: String,
pub url: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::messaging_card::types::{MessageCardKind, OauthPrompt};
#[test]
fn auth_spec_defaults_title() {
let oauth = OauthCard {
provider: OauthProvider::Microsoft,
scopes: vec!["User.Read".into()],
resource: None,
prompt: Some(OauthPrompt::Consent),
start_url: Some("https://auth/start".into()),
connection_name: Some("graph".into()),
metadata: None,
};
let card = MessageCard {
kind: MessageCardKind::Oauth,
title: None,
text: None,
footer: None,
images: Vec::new(),
actions: Vec::new(),
allow_markdown: true,
#[cfg(feature = "adaptive-cards")]
adaptive: None,
oauth: Some(oauth.clone()),
};
let spec = AuthRenderSpec::from_card(&card, card.oauth.as_ref().unwrap());
assert_eq!(spec.provider, OauthProvider::Microsoft);
assert_eq!(spec.scopes, vec!["User.Read".to_string()]);
assert_eq!(
spec.fallback_button.title,
"Sign in with Microsoft".to_string()
);
assert_eq!(
spec.fallback_button.url,
Some("https://auth/start".to_string())
);
assert_eq!(spec.connection_name.as_deref(), Some("graph"));
assert_eq!(spec.prompt, Some(OauthPrompt::Consent));
}
}