mod agent;
pub use agent::*;
use crate::{
agent::{AgentConfiguration, Client, LoginOptions, LogoutOptions, OAuth2Operations},
context::{LatestAccessToken, OAuth2Context},
};
use agent::Agent as AgentContext;
use std::time::Duration;
use yew::prelude::*;
#[derive(Clone, Debug, Properties)]
pub struct OAuth2Properties<C: Client> {
pub config: C::Configuration,
#[prop_or_default]
pub scopes: Vec<String>,
#[prop_or(Duration::from_secs(30))]
pub grace_period: Duration,
#[prop_or_default]
pub max_expiration: Option<Duration>,
#[prop_or_default]
pub audience: Option<String>,
#[prop_or_default]
pub children: Children,
#[prop_or_default]
pub login_options: Option<LoginOptions>,
#[prop_or_default]
pub logout_options: Option<LogoutOptions>,
}
impl<C: Client> PartialEq for OAuth2Properties<C> {
fn eq(&self, other: &Self) -> bool {
self.config == other.config
&& self.scopes == other.scopes
&& self.grace_period == other.grace_period
&& self.max_expiration == other.max_expiration
&& self.audience == other.audience
&& self.children == other.children
}
}
pub struct OAuth2<C: Client> {
context: OAuth2Context,
latest_access_token: LatestAccessToken,
agent: AgentContext<C>,
config: AgentConfiguration<C>,
}
#[doc(hidden)]
pub enum Msg {
Context(OAuth2Context),
}
impl<C: Client> Component for OAuth2<C> {
type Message = Msg;
type Properties = OAuth2Properties<C>;
fn create(ctx: &Context<Self>) -> Self {
let config = Self::make_config(ctx.props());
let callback = ctx.link().callback(Msg::Context);
let agent = crate::agent::Agent::new(move |s| callback.emit(s));
let _ = agent.configure(config.clone());
Self {
context: OAuth2Context::NotInitialized,
latest_access_token: LatestAccessToken {
access_token: Default::default(),
},
agent: AgentContext::new(agent),
config,
}
}
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Self::Message::Context(context) => {
if self.context != context {
self.latest_access_token
.set_access_token(context.access_token());
self.context = context;
return true;
}
}
}
false
}
fn changed(&mut self, ctx: &Context<Self>, _: &Self::Properties) -> bool {
let config = Self::make_config(ctx.props());
if self.config != config {
let _ = self.agent.configure(config.clone());
self.config = config;
}
true
}
fn view(&self, ctx: &Context<Self>) -> Html {
html!(
<>
<ContextProvider<OAuth2Context> context={self.context.clone()}>
<ContextProvider<AgentContext<C>> context={self.agent.clone()}>
<ContextProvider<LatestAccessToken>
context={self.latest_access_token.clone()}
>
{ for ctx.props().children.iter() }
</ContextProvider<LatestAccessToken>>
</ContextProvider<AgentContext<C>>>
</ContextProvider<OAuth2Context>>
</>
)
}
}
impl<C: Client> OAuth2<C> {
fn make_config(props: &OAuth2Properties<C>) -> AgentConfiguration<C> {
AgentConfiguration {
config: props.config.clone(),
scopes: props.scopes.clone(),
grace_period: props.grace_period,
max_expiration: props.max_expiration,
audience: props.audience.clone(),
default_login_options: props.login_options.clone(),
default_logout_options: props.logout_options.clone(),
}
}
}
#[cfg(feature = "openid")]
pub mod openid {
pub type OAuth2 = super::OAuth2<crate::agent::client::OpenIdClient>;
}
pub mod oauth2 {
pub type OAuth2 = super::OAuth2<crate::agent::client::OAuth2Client>;
}