Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/leptos-actix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ leptos_actix = { workspace = true, optional = true }
leptos_meta.workspace = true
leptos_router.workspace = true
shield.workspace = true
# shield-bootstrap = { workspace = true, features = ["leptos"] }
shield-leptos.workspace = true
shield-leptos-actix = { workspace = true, optional = true }
shield-memory = { workspace = true, optional = true }
Expand Down
4 changes: 2 additions & 2 deletions examples/leptos-actix/src/home.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use leptos::{either::Either, prelude::*};
use leptos_router::components::A;
use shield_leptos::integration::LeptosUser;
use shield_leptos::LeptosUser;

#[server]
pub async fn user() -> Result<Option<LeptosUser>, ServerFnError> {
use shield_leptos::context::extract_user;
use shield_leptos::extract_user;

Ok(extract_user().await)
}
Expand Down
1 change: 1 addition & 0 deletions examples/leptos-axum/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ leptos_axum = { workspace = true, optional = true }
leptos_meta.workspace = true
leptos_router.workspace = true
shield.workspace = true
# shield-bootstrap = { workspace = true, features = ["leptos"] }
shield-leptos.workspace = true
shield-leptos-axum = { workspace = true, features = [
"utoipa",
Expand Down
4 changes: 2 additions & 2 deletions examples/leptos-axum/src/home.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use leptos::{either::Either, prelude::*};
use leptos_router::components::A;
use shield_leptos::integration::LeptosUser;
use shield_leptos::LeptosUser;

#[server]
pub async fn user() -> Result<Option<LeptosUser>, ServerFnError> {
use shield_leptos::context::extract_user;
use shield_leptos::extract_user;

Ok(extract_user().await)
}
Expand Down
1 change: 1 addition & 0 deletions packages/core/shield/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ futures.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
thiserror.workspace = true
tracing.workspace = true
utoipa = { workspace = true, optional = true }
9 changes: 9 additions & 0 deletions packages/core/shield/src/action.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
use std::any::Any;

use async_trait::async_trait;
use serde::{Deserialize, Serialize};

use crate::{
error::ShieldError, form::Form, provider::Provider, request::Request, response::Response,
session::Session,
};

// TODO: Think of a better name.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ActionForms {
pub id: String,
pub name: String,
pub forms: Vec<Form>,
}

#[async_trait]
pub trait Action<P: Provider>: ErasedAction + Send + Sync {
fn id(&self) -> String;
Expand Down
22 changes: 18 additions & 4 deletions packages/core/shield/src/shield.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::{any::Any, collections::HashMap, sync::Arc};

use futures::future::try_join_all;
use tracing::warn;

use crate::{
Session, error::ShieldError, form::Form, method::ErasedMethod, options::ShieldOptions,
storage::Storage, user::User,
action::ActionForms, error::ShieldError, method::ErasedMethod, options::ShieldOptions,
session::Session, storage::Storage, user::User,
};

#[derive(Clone)]
Expand Down Expand Up @@ -68,14 +69,23 @@ impl<U: User> Shield<U> {
&self,
action_id: &str,
session: Session,
) -> Result<Vec<Form>, ShieldError> {
) -> Result<ActionForms, ShieldError> {
let mut action_name = None::<String>;
let mut forms = vec![];

for (_, method) in self.methods.iter() {
let Some(action) = method.erased_action_by_id(action_id) else {
continue;
};

let name = action.erased_name();
if let Some(action_name) = &action_name {
if *action_name != name {
warn!("Action name mismatch `{}` != `{}`", action_name, name);
}
}
action_name = Some(name);

for provider in method.erased_providers().await? {
if !action.erased_condition(&*provider, session.clone())? {
continue;
Expand All @@ -87,7 +97,11 @@ impl<U: User> Shield<U> {
}
}

Ok(forms)
Ok(ActionForms {
id: action_id.to_owned(),
name: action_name.unwrap_or(action_id.to_owned()),
forms,
})
}
}

Expand Down
10 changes: 6 additions & 4 deletions packages/core/shield/src/shield_dyn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use std::{any::Any, sync::Arc};

use async_trait::async_trait;

use crate::{Session, error::ShieldError, form::Form, shield::Shield, user::User};
use crate::{
action::ActionForms, error::ShieldError, session::Session, shield::Shield, user::User,
};

#[async_trait]
pub trait DynShield: Send + Sync {
Expand All @@ -12,7 +14,7 @@ pub trait DynShield: Send + Sync {
&self,
action_id: &str,
session: Session,
) -> Result<Vec<Form>, ShieldError>;
) -> Result<ActionForms, ShieldError>;
}

#[async_trait]
Expand All @@ -25,7 +27,7 @@ impl<U: User> DynShield for Shield<U> {
&self,
action_id: &str,
session: Session,
) -> Result<Vec<Form>, ShieldError> {
) -> Result<ActionForms, ShieldError> {
self.action_forms(action_id, session).await
}
}
Expand All @@ -45,7 +47,7 @@ impl ShieldDyn {
&self,
action_id: &str,
session: Session,
) -> Result<Vec<Form>, ShieldError> {
) -> Result<ActionForms, ShieldError> {
self.0.action_forms(action_id, session).await
}
}
11 changes: 5 additions & 6 deletions packages/integrations/shield-dioxus/src/routes/action.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use dioxus::prelude::*;
use shield::Form;
use shield::ActionForms;

use crate::{DioxusIntegrationDyn, form::ToRsx};
use crate::{DioxusIntegrationDyn, ErasedDioxusStyle};

#[derive(Clone, PartialEq, Props)]
pub struct ActionProps {
Expand All @@ -15,20 +15,19 @@ pub fn Action(props: ActionProps) -> Element {

move || forms(action_id.clone())
})?;
let style = use_context::<ErasedDioxusStyle>();

let response_read = response.read();
let response = response_read.as_ref().unwrap();

match response {
Ok(forms) => rsx! {
{forms.iter().map(ToRsx::to_rsx)}
},
Ok(forms) => style.render(forms),
Err(err) => rsx! { "{err}" },
}
}

#[server]
async fn forms(action_id: String) -> Result<Vec<Form>, ServerFnError> {
async fn forms(action_id: String) -> Result<ActionForms, ServerFnError> {
let FromContext(integration): FromContext<DioxusIntegrationDyn> = extract().await?;
let shield = integration.extract_shield().await;
let session = integration.extract_session().await;
Expand Down
8 changes: 4 additions & 4 deletions packages/integrations/shield-dioxus/src/style.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::sync::Arc;

use dioxus::prelude::Element;
use shield::Form;
use shield::ActionForms;

pub trait DioxusStyle: Send + Sync {
fn render(&self, forms: &[Form]) -> Element;
fn render(&self, action: &ActionForms) -> Element;
}

#[derive(Clone)]
Expand All @@ -15,7 +15,7 @@ impl ErasedDioxusStyle {
Self(Arc::new(integration))
}

pub fn render(&self, forms: &[Form]) -> Element {
self.0.render(forms)
pub fn render(&self, action: &ActionForms) -> Element {
self.0.render(action)
}
}
10 changes: 5 additions & 5 deletions packages/integrations/shield-leptos-actix/src/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ use leptos::prelude::provide_context;
use leptos_actix::{extract, redirect};
use shield::{Session, ShieldDyn, User};
use shield_actix::{ExtractSession, ExtractShield, ExtractUser};
use shield_leptos::integration::{LeptosIntegration, LeptosUser};
use shield_leptos::{LeptosIntegration, LeptosUser};

pub struct LeptosActixIntegration<U: User>(PhantomData<U>);
pub struct ActixLeptosIntegration<U: User>(PhantomData<U>);

impl<U: User> Default for LeptosActixIntegration<U> {
impl<U: User> Default for ActixLeptosIntegration<U> {
fn default() -> Self {
Self(Default::default())
}
}

#[async_trait]
impl<U: User + Clone + 'static> LeptosIntegration for LeptosActixIntegration<U> {
impl<U: User + Clone + 'static> LeptosIntegration for ActixLeptosIntegration<U> {
async fn extract_shield(&self) -> ShieldDyn {
let ExtractShield(shield) = extract::<ExtractShield<U>>().await.expect("TOD");

Expand All @@ -41,5 +41,5 @@ impl<U: User + Clone + 'static> LeptosIntegration for LeptosActixIntegration<U>
}

pub fn provide_actix_integration<U: User + Clone + 'static>() {
provide_context::<Arc<dyn LeptosIntegration>>(Arc::new(LeptosActixIntegration::<U>::default()));
provide_context::<Arc<dyn LeptosIntegration>>(Arc::new(ActixLeptosIntegration::<U>::default()));
}
10 changes: 5 additions & 5 deletions packages/integrations/shield-leptos-axum/src/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ use leptos::prelude::provide_context;
use leptos_axum::{extract, redirect};
use shield::{Session, ShieldDyn, User};
use shield_axum::{ExtractSession, ExtractShield, ExtractUser};
use shield_leptos::integration::{LeptosIntegration, LeptosUser};
use shield_leptos::{LeptosIntegration, LeptosUser};

pub struct LeptosAxumIntegration<U: User>(PhantomData<U>);
pub struct AxumLeptosIntegration<U: User>(PhantomData<U>);

impl<U: User> Default for LeptosAxumIntegration<U> {
impl<U: User> Default for AxumLeptosIntegration<U> {
fn default() -> Self {
Self(Default::default())
}
}

#[async_trait]
impl<U: User + Clone + 'static> LeptosIntegration for LeptosAxumIntegration<U> {
impl<U: User + Clone + 'static> LeptosIntegration for AxumLeptosIntegration<U> {
async fn extract_shield(&self) -> ShieldDyn {
let ExtractShield(shield) = extract::<ExtractShield<U>>().await.expect("TODO");

Expand All @@ -41,5 +41,5 @@ impl<U: User + Clone + 'static> LeptosIntegration for LeptosAxumIntegration<U> {
}

pub fn provide_axum_integration<U: User + Clone + 'static>() {
provide_context::<Arc<dyn LeptosIntegration>>(Arc::new(LeptosAxumIntegration::<U>::default()));
provide_context::<Arc<dyn LeptosIntegration>>(Arc::new(AxumLeptosIntegration::<U>::default()));
}
9 changes: 7 additions & 2 deletions packages/integrations/shield-leptos/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
pub mod context;
pub mod integration;
mod context;
mod integration;
mod style;

pub use context::*;
pub use integration::*;
pub use style::*;
21 changes: 21 additions & 0 deletions packages/integrations/shield-leptos/src/style.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use std::sync::Arc;

use leptos::prelude::AnyView;
use shield::ActionForms;

pub trait LeptosStyle: Send + Sync {
fn render(&self, action: &ActionForms) -> AnyView;
}

#[derive(Clone)]
pub struct ErasedLeptosStyle(Arc<dyn LeptosStyle>);

impl ErasedLeptosStyle {
pub fn new<I: LeptosStyle + 'static>(integration: I) -> Self {
Self(Arc::new(integration))
}

pub fn render(&self, action: &ActionForms) -> AnyView {
self.0.render(action)
}
}
3 changes: 3 additions & 0 deletions packages/styles/shield-bootstrap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ version.workspace = true

[features]
dioxus = ["dep:dioxus", "dep:shield-dioxus"]
leptos = ["dep:leptos", "dep:shield-leptos"]

[dependencies]
dioxus = { workspace = true, optional = true }
leptos = { workspace = true, optional = true }
shield.workspace = true
shield-dioxus = { workspace = true, optional = true }
shield-leptos = { workspace = true, optional = true }
9 changes: 4 additions & 5 deletions packages/styles/shield-bootstrap/src/dioxus.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use dioxus::prelude::*;
use shield::Form;
use shield::ActionForms;
use shield_dioxus::{DioxusStyle, ErasedDioxusStyle};

#[derive(Default)]
Expand All @@ -12,17 +12,16 @@ impl BootstrapDioxusStyle {
}

impl DioxusStyle for BootstrapDioxusStyle {
fn render(&self, forms: &[Form]) -> Element {
fn render(&self, action: &ActionForms) -> Element {
rsx! {
div {
class: "container",

h1 {
// TODO: Get from action.
"Sign in"
"{action.name}"
}

for form in forms {
for form in &action.forms {
form {
for input in &form.inputs {
div {
Expand Down
Loading