Skip to content

Commit 1916ce5

Browse files
feat(shield): add default action implementations (#129)
1 parent 3aa6e0d commit 1916ce5

20 files changed

Lines changed: 271 additions & 45 deletions

File tree

packages/core/shield/src/action.rs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ use crate::{
77
session::Session,
88
};
99

10-
pub const SIGN_IN_ACTION_ID: &str = "sign-in";
11-
pub const SIGN_IN_CALLBACK_ACTION_ID: &str = "sign-in-callback";
12-
pub const SIGN_OUT_ACTION_ID: &str = "sign-out";
13-
1410
#[async_trait]
1511
pub trait Action<P: Provider>: ErasedAction + Send + Sync {
1612
fn id(&self) -> String;
1713

14+
fn name(&self) -> String;
15+
16+
fn condition(&self, _provider: &P, _session: Session) -> Result<bool, ShieldError> {
17+
Ok(true)
18+
}
19+
1820
fn form(&self, provider: P) -> Form;
1921

2022
async fn call(
@@ -29,6 +31,14 @@ pub trait Action<P: Provider>: ErasedAction + Send + Sync {
2931
pub trait ErasedAction: Send + Sync {
3032
fn erased_id(&self) -> String;
3133

34+
fn erased_name(&self) -> String;
35+
36+
fn erased_condition(
37+
&self,
38+
provider: &(dyn Any + Send + Sync),
39+
session: Session,
40+
) -> Result<bool, ShieldError>;
41+
3242
fn erased_form(&self, provider: Box<dyn Any + Send + Sync>) -> Form;
3343

3444
async fn erased_call(
@@ -48,6 +58,14 @@ macro_rules! erased_action {
4858
self.id()
4959
}
5060

61+
fn erased_name(&self) -> String {
62+
self.name()
63+
}
64+
65+
fn erased_condition(&self, provider: &(dyn std::any::Any + Send + Sync), session: $crate::Session) -> Result<bool, $crate::ShieldError> {
66+
self.condition(provider.downcast_ref().expect("TODO"), session)
67+
}
68+
5169
fn erased_form(&self, provider: Box<dyn std::any::Any + Send + Sync>) -> $crate::Form {
5270
self.form(*provider.downcast().expect("TODO"))
5371
}
@@ -57,7 +75,7 @@ macro_rules! erased_action {
5775
provider: Box<dyn std::any::Any + Send + Sync>,
5876
session: $crate::Session,
5977
request: $crate::Request,
60-
) -> Result<$crate::Response, ShieldError> {
78+
) -> Result<$crate::Response, $crate::ShieldError> {
6179
self.call(*provider.downcast().expect("TODO"), session, request)
6280
.await
6381
}
@@ -76,7 +94,8 @@ pub(crate) mod tests {
7694

7795
use super::Action;
7896

79-
pub const TEST_ACTION_ID: &str = "action";
97+
pub const TEST_ACTION_ID: &str = "test";
98+
pub const TEST_ACTION_NAME: &str = "Test";
8099

81100
#[derive(Default)]
82101
pub struct TestAction {}
@@ -87,6 +106,10 @@ pub(crate) mod tests {
87106
TEST_ACTION_ID.to_owned()
88107
}
89108

109+
fn name(&self) -> String {
110+
TEST_ACTION_NAME.to_owned()
111+
}
112+
90113
fn form(&self, _provider: TestProvider) -> Form {
91114
Form { inputs: vec![] }
92115
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
mod sign_in;
2+
mod sign_in_callback;
3+
mod sign_out;
4+
5+
pub use sign_in::*;
6+
pub use sign_in_callback::*;
7+
pub use sign_out::*;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const ACTION_ID: &str = "sign-in";
2+
const ACTION_NAME: &str = "Sign in";
3+
4+
pub struct SignInAction;
5+
6+
impl SignInAction {
7+
pub fn id() -> String {
8+
ACTION_ID.to_owned()
9+
}
10+
11+
pub fn name() -> String {
12+
ACTION_NAME.to_owned()
13+
}
14+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use crate::{Provider, Session, ShieldError};
2+
3+
const ACTION_ID: &str = "sign-in-callback";
4+
const ACTION_NAME: &str = "Sign in callback";
5+
6+
pub struct SignInCallbackAction;
7+
8+
impl SignInCallbackAction {
9+
pub fn id() -> String {
10+
ACTION_ID.to_owned()
11+
}
12+
13+
pub fn name() -> String {
14+
ACTION_NAME.to_owned()
15+
}
16+
17+
pub fn condition<P: Provider>(_provider: &P, _session: Session) -> Result<bool, ShieldError> {
18+
Ok(false)
19+
}
20+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use crate::{
2+
Form, Input, InputType, InputTypeSubmit, Provider, Session, SessionError, ShieldError,
3+
};
4+
5+
const ACTION_ID: &str = "sign-out";
6+
const ACTION_NAME: &str = "Sign out";
7+
8+
pub struct SignOutAction;
9+
10+
impl SignOutAction {
11+
pub fn id() -> String {
12+
ACTION_ID.to_owned()
13+
}
14+
15+
pub fn name() -> String {
16+
ACTION_NAME.to_owned()
17+
}
18+
19+
pub fn condition<P: Provider>(provider: &P, session: Session) -> Result<bool, ShieldError> {
20+
let session_data = session.data();
21+
let session_data = session_data
22+
.lock()
23+
.map_err(|err| SessionError::Lock(err.to_string()))?;
24+
25+
Ok(session_data
26+
.authentication
27+
.as_ref()
28+
.is_some_and(|authentication| {
29+
authentication.method_id == provider.method_id()
30+
&& authentication.provider_id == provider.id()
31+
}))
32+
}
33+
34+
pub fn form<P: Provider>(_provider: P) -> Form {
35+
Form {
36+
inputs: vec![Input {
37+
name: "submit".to_owned(),
38+
label: None,
39+
r#type: InputType::Submit(InputTypeSubmit {}),
40+
value: Some(Self::name()),
41+
}],
42+
}
43+
}
44+
}

packages/core/shield/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod action;
2+
mod actions;
23
mod error;
34
mod form;
45
mod method;
@@ -13,6 +14,7 @@ mod storage;
1314
mod user;
1415

1516
pub use action::*;
17+
pub use actions::*;
1618
pub use error::*;
1719
pub use form::*;
1820
pub use method::*;

packages/core/shield/src/shield.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::{any::Any, collections::HashMap, sync::Arc};
33
use futures::future::try_join_all;
44

55
use crate::{
6-
error::ShieldError, form::Form, method::ErasedMethod, options::ShieldOptions, storage::Storage,
7-
user::User,
6+
Session, error::ShieldError, form::Form, method::ErasedMethod, options::ShieldOptions,
7+
storage::Storage, user::User,
88
};
99

1010
#[derive(Clone)]
@@ -64,7 +64,11 @@ impl<U: User> Shield<U> {
6464
}
6565
}
6666

67-
pub async fn action_forms(&self, action_id: &str) -> Result<Vec<Form>, ShieldError> {
67+
pub async fn action_forms(
68+
&self,
69+
action_id: &str,
70+
session: Session,
71+
) -> Result<Vec<Form>, ShieldError> {
6872
let mut forms = vec![];
6973

7074
for (_, method) in self.methods.iter() {
@@ -73,6 +77,10 @@ impl<U: User> Shield<U> {
7377
};
7478

7579
for provider in method.erased_providers().await? {
80+
if !action.erased_condition(&provider, session.clone())? {
81+
continue;
82+
}
83+
7684
let form = action.erased_form(provider);
7785

7886
forms.push(form);

packages/core/shield/src/shield_dyn.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ use std::{any::Any, sync::Arc};
22

33
use async_trait::async_trait;
44

5-
use crate::{error::ShieldError, form::Form, shield::Shield, user::User};
5+
use crate::{Session, error::ShieldError, form::Form, shield::Shield, user::User};
66

77
#[async_trait]
88
pub trait DynShield: Send + Sync {
99
async fn providers(&self) -> Result<Vec<Box<dyn Any + Send + Sync>>, ShieldError>;
1010

11-
async fn action_forms(&self, action_id: &str) -> Result<Vec<Form>, ShieldError>;
11+
async fn action_forms(
12+
&self,
13+
action_id: &str,
14+
session: Session,
15+
) -> Result<Vec<Form>, ShieldError>;
1216
}
1317

1418
#[async_trait]
@@ -17,8 +21,12 @@ impl<U: User> DynShield for Shield<U> {
1721
self.providers().await
1822
}
1923

20-
async fn action_forms(&self, action_id: &str) -> Result<Vec<Form>, ShieldError> {
21-
self.action_forms(action_id).await
24+
async fn action_forms(
25+
&self,
26+
action_id: &str,
27+
session: Session,
28+
) -> Result<Vec<Form>, ShieldError> {
29+
self.action_forms(action_id, session).await
2230
}
2331
}
2432

@@ -33,7 +41,11 @@ impl ShieldDyn {
3341
self.0.providers().await
3442
}
3543

36-
pub async fn action_forms(&self, action_id: &str) -> Result<Vec<Form>, ShieldError> {
37-
self.0.action_forms(action_id).await
44+
pub async fn action_forms(
45+
&self,
46+
action_id: &str,
47+
session: Session,
48+
) -> Result<Vec<Form>, ShieldError> {
49+
self.0.action_forms(action_id, session).await
3850
}
3951
}

packages/integrations/shield-dioxus/src/integration.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@ impl DioxusIntegrationDyn {
2121
pub async fn extract_shield(&self) -> ShieldDyn {
2222
self.0.extract_shield().await
2323
}
24+
25+
pub async fn extract_session(&self) -> Session {
26+
self.0.extract_session().await
27+
}
2428
}

packages/integrations/shield-dioxus/src/routes/action.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ pub fn Action(props: ActionProps) -> Element {
3131
async fn forms(action_id: String) -> Result<Vec<Form>, ServerFnError> {
3232
let FromContext(integration): FromContext<DioxusIntegrationDyn> = extract().await?;
3333
let shield = integration.extract_shield().await;
34+
let session = integration.extract_session().await;
3435

35-
let forms = shield.action_forms(&action_id).await?;
36+
let forms = shield.action_forms(&action_id, session).await?;
3637

3738
Ok(forms)
3839
}

0 commit comments

Comments
 (0)