Skip to content

Commit 40f4864

Browse files
feat: add user connections
1 parent d25ea57 commit 40f4864

14 files changed

Lines changed: 204 additions & 3 deletions

File tree

packages/core/shield/src/method.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ use async_trait::async_trait;
44
use serde::{Serialize, de::DeserializeOwned};
55

66
use crate::{
7-
ErasedMethodAction,
8-
action::MethodAction,
7+
action::{ErasedMethodAction, MethodAction},
98
error::{SessionError, ShieldError},
109
provider::Provider,
1110
};
1211

1312
#[async_trait]
1413
pub trait Method: Send + Sync {
1514
type Provider: Provider;
15+
type Connection;
1616
type Session: DeserializeOwned + Serialize;
1717

1818
fn id(&self) -> String;
@@ -40,6 +40,12 @@ pub trait Method: Send + Sync {
4040
.into_iter()
4141
.find(|provider| provider.id().as_deref() == provider_id))
4242
}
43+
44+
async fn user_connections(
45+
&self,
46+
user: &str,
47+
provider_id: Option<&str>,
48+
) -> Result<Vec<Self::Connection>, ShieldError>;
4349
}
4450

4551
#[async_trait]
@@ -59,6 +65,12 @@ pub trait ErasedMethod: Send + Sync {
5965
provider_id: Option<&str>,
6066
) -> Result<Option<Box<dyn Any + Send + Sync>>, ShieldError>;
6167

68+
async fn erased_user_connections(
69+
&self,
70+
user_id: &str,
71+
provider_id: Option<&str>,
72+
) -> Result<Vec<Box<dyn Any + Send + Sync>>, ShieldError>;
73+
6274
fn erased_deserialize_session(
6375
&self,
6476
value: Option<&str>,
@@ -110,6 +122,18 @@ macro_rules! erased_method {
110122
})
111123
}
112124

125+
async fn erased_user_connections(
126+
&self,
127+
user_id: &str,
128+
provider_id: Option<&str>,
129+
) -> Result<Vec<Box<dyn std::any::Any + Send + Sync>>, $crate::ShieldError> {
130+
Ok(self.user_connections(user_id, provider_id)
131+
.await?
132+
.into_iter()
133+
.map(|connection| Box::new(connection) as Box<dyn std::any::Any + Send + Sync>)
134+
.collect())
135+
}
136+
113137
fn erased_deserialize_session(
114138
&self,
115139
value: Option<&str>

packages/core/shield/src/shield.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use utoipa::{
1616
#[cfg(feature = "utoipa")]
1717
use crate::path::{ActionPathParams, MethodActionPathParams};
1818
use crate::{
19-
SignOutAction,
2019
action::{Action, ActionForms, ActionMethodForm, ActionProviderForm},
20+
actions::SignOutAction,
2121
error::{ActionError, MethodError, ProviderError, SessionError, ShieldError},
2222
method::ErasedMethod,
2323
options::ShieldOptions,
@@ -277,6 +277,32 @@ impl<U: User> Shield<U> {
277277
}
278278
}
279279

280+
pub async fn user_connections<C: 'static>(
281+
&self,
282+
user: &U,
283+
method_id: &str,
284+
provider_id: Option<&str>,
285+
) -> Result<Vec<C>, ShieldError> {
286+
let method =
287+
self.method_by_id(method_id)
288+
.ok_or(ShieldError::Method(MethodError::NotFound(
289+
method_id.to_owned(),
290+
)))?;
291+
292+
let connections = method
293+
.erased_user_connections(&user.id(), provider_id)
294+
.await?;
295+
296+
Ok(connections
297+
.into_iter()
298+
.map(|connection| {
299+
*connection
300+
.downcast::<C>()
301+
.expect("Connection should be downcast")
302+
})
303+
.collect())
304+
}
305+
280306
#[cfg(feature = "utoipa")]
281307
pub fn openapi(&self) -> OpenApi {
282308
use utoipa::openapi::Response;

packages/methods/shield-credentials/src/method.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ impl<U: User, D: DeserializeOwned> CredentialsMethod<U, D> {
2525
#[async_trait]
2626
impl<U: User + 'static, D: DeserializeOwned + 'static> Method for CredentialsMethod<U, D> {
2727
type Provider = CredentialsProvider;
28+
type Connection = ();
2829
type Session = ();
2930

3031
fn id(&self) -> String {
@@ -40,6 +41,14 @@ impl<U: User + 'static, D: DeserializeOwned + 'static> Method for CredentialsMet
4041
async fn providers(&self) -> Result<Vec<Self::Provider>, ShieldError> {
4142
Ok(vec![CredentialsProvider])
4243
}
44+
45+
async fn user_connections(
46+
&self,
47+
_user_id: &str,
48+
_provider_id: Option<&str>,
49+
) -> Result<Vec<Self::Connection>, ShieldError> {
50+
Ok(vec![])
51+
}
4352
}
4453

4554
erased_method!(CredentialsMethod, <U: User, D: DeserializeOwned>);

packages/methods/shield-dummy/src/method.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ impl<U: User> DummyMethod<U> {
2222
#[async_trait]
2323
impl<U: User + 'static> Method for DummyMethod<U> {
2424
type Provider = DummyProvider;
25+
type Connection = ();
2526
type Session = ();
2627

2728
fn id(&self) -> String {
@@ -35,6 +36,14 @@ impl<U: User + 'static> Method for DummyMethod<U> {
3536
async fn providers(&self) -> Result<Vec<Self::Provider>, ShieldError> {
3637
Ok(vec![DummyProvider])
3738
}
39+
40+
async fn user_connections(
41+
&self,
42+
_user_id: &str,
43+
_provider_id: Option<&str>,
44+
) -> Result<Vec<Self::Connection>, ShieldError> {
45+
Ok(vec![])
46+
}
3847
}
3948

4049
erased_method!(DummyMethod, <U: User>);

packages/methods/shield-email/src/method.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ impl<U: User> EmailMethod<U> {
2929
#[async_trait]
3030
impl<U: User + 'static> Method for EmailMethod<U> {
3131
type Provider = EmailProvider;
32+
type Connection = ();
3233
type Session = ();
3334

3435
fn id(&self) -> String {
@@ -51,6 +52,14 @@ impl<U: User + 'static> Method for EmailMethod<U> {
5152
async fn providers(&self) -> Result<Vec<Self::Provider>, ShieldError> {
5253
Ok(vec![EmailProvider])
5354
}
55+
56+
async fn user_connections(
57+
&self,
58+
_user_id: &str,
59+
_provider_id: Option<&str>,
60+
) -> Result<Vec<Self::Connection>, ShieldError> {
61+
Ok(vec![])
62+
}
5463
}
5564

5665
erased_method!(EmailMethod, <U: User>);

packages/methods/shield-oauth/src/method.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use async_trait::async_trait;
44
use shield::{Method, MethodAction, ShieldError, User, erased_method};
55

66
use crate::{
7+
OauthConnection,
78
actions::{OauthSignInAction, OauthSignInCallbackAction},
89
options::OauthOptions,
910
provider::OauthProvider,
@@ -67,6 +68,7 @@ impl<U: User> OauthMethod<U> {
6768
#[async_trait]
6869
impl<U: User + 'static> Method for OauthMethod<U> {
6970
type Provider = OauthProvider;
71+
type Connection = OauthConnection;
7072
type Session = OauthSession;
7173

7274
fn id(&self) -> String {
@@ -102,6 +104,17 @@ impl<U: User + 'static> Method for OauthMethod<U> {
102104
Ok(None)
103105
}
104106
}
107+
108+
async fn user_connections(
109+
&self,
110+
user_id: &str,
111+
provider_id: Option<&str>,
112+
) -> Result<Vec<Self::Connection>, ShieldError> {
113+
Ok(self
114+
.storage
115+
.user_oauth_connections(user_id, provider_id)
116+
.await?)
117+
}
105118
}
106119

107120
erased_method!(OauthMethod, <U: User>);

packages/methods/shield-oauth/src/storage.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,10 @@ pub trait OauthStorage<U: User>: Storage<U> + Sync {
3838
) -> Result<OauthConnection, StorageError>;
3939

4040
async fn delete_oauth_connection(&self, connection_id: &str) -> Result<(), StorageError>;
41+
42+
async fn user_oauth_connections(
43+
&self,
44+
user_id: &str,
45+
provider_id: Option<&str>,
46+
) -> Result<Vec<OauthConnection>, StorageError>;
4147
}

packages/methods/shield-oidc/src/method.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use async_trait::async_trait;
44
use shield::{Method, MethodAction, ShieldError, User, erased_method};
55

66
use crate::{
7+
OidcConnection,
78
actions::{OidcSignInAction, OidcSignInCallbackAction},
89
options::OidcOptions,
910
provider::OidcProvider,
@@ -65,6 +66,7 @@ impl<U: User> OidcMethod<U> {
6566
#[async_trait]
6667
impl<U: User + 'static> Method for OidcMethod<U> {
6768
type Provider = OidcProvider;
69+
type Connection = OidcConnection;
6870
type Session = OidcSession;
6971

7072
fn id(&self) -> String {
@@ -100,6 +102,17 @@ impl<U: User + 'static> Method for OidcMethod<U> {
100102
Ok(None)
101103
}
102104
}
105+
106+
async fn user_connections(
107+
&self,
108+
user_id: &str,
109+
provider_id: Option<&str>,
110+
) -> Result<Vec<Self::Connection>, ShieldError> {
111+
Ok(self
112+
.storage
113+
.user_oidc_connections(user_id, provider_id)
114+
.await?)
115+
}
103116
}
104117

105118
erased_method!(OidcMethod, <U: User>);

packages/methods/shield-oidc/src/storage.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,10 @@ pub trait OidcStorage<U: User>: Storage<U> + Sync {
3838
) -> Result<OidcConnection, StorageError>;
3939

4040
async fn delete_oidc_connection(&self, connection_id: &str) -> Result<(), StorageError>;
41+
42+
async fn user_oidc_connections(
43+
&self,
44+
user_id: &str,
45+
provider_id: Option<&str>,
46+
) -> Result<Vec<OidcConnection>, StorageError>;
4147
}

packages/methods/shield-workos/src/method.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ impl WorkosMethod {
4141
#[async_trait]
4242
impl Method for WorkosMethod {
4343
type Provider = WorkosProvider;
44+
type Connection = ();
4445
type Session = ();
4546

4647
fn id(&self) -> String {
@@ -61,6 +62,15 @@ impl Method for WorkosMethod {
6162
async fn providers(&self) -> Result<Vec<Self::Provider>, ShieldError> {
6263
Ok(vec![WorkosProvider])
6364
}
65+
66+
async fn user_connections(
67+
&self,
68+
_user_id: &str,
69+
_provider_id: Option<&str>,
70+
) -> Result<Vec<Self::Connection>, ShieldError> {
71+
// TODO
72+
Ok(vec![])
73+
}
6474
}
6575

6676
erased_method!(WorkosMethod);

0 commit comments

Comments
 (0)