Support guard simple rule with the rework (recursivity)
This commit is contained in:
parent
3581008e71
commit
216b363ce7
|
@ -121,52 +121,87 @@ pub fn generate_guards(
|
||||||
crate_name: &TokenStream,
|
crate_name: &TokenStream,
|
||||||
args: &Meta,
|
args: &Meta,
|
||||||
) -> GeneratorResult<Option<TokenStream>> {
|
) -> GeneratorResult<Option<TokenStream>> {
|
||||||
|
println!("{:#?}\n", args);
|
||||||
match args {
|
match args {
|
||||||
Meta::List(args) => {
|
Meta::List(args) => {
|
||||||
let mut guards = None;
|
println!("args = {:#?}\n", args.path);
|
||||||
for item in &args.nested {
|
match args.path.get_ident() {
|
||||||
if let NestedMeta::Meta(Meta::List(ls)) = item {
|
Some(ident) => {
|
||||||
let ty = &ls.path;
|
match ident.to_string().as_str() {
|
||||||
let mut params = Vec::new();
|
"guard" => {
|
||||||
for attr in &ls.nested {
|
println!("ident guard found {:#?}\n", ident);
|
||||||
if let NestedMeta::Meta(Meta::NameValue(nv)) = attr {
|
if args.nested.len() > 1 {
|
||||||
let name = &nv.path;
|
return Err(Error::new_spanned(args, "Chained rules isn't possible anymore, please use operators.").into());
|
||||||
if let Lit::Str(value) = &nv.lit {
|
|
||||||
let value_str = value.value();
|
|
||||||
if value_str.starts_with('@') {
|
|
||||||
let getter_name = get_param_getter_ident(&value_str[1..]);
|
|
||||||
params.push(quote! { #name: #getter_name()? });
|
|
||||||
} else {
|
|
||||||
let expr = syn::parse_str::<Expr>(&value_str)?;
|
|
||||||
params.push(quote! { #name: (#expr).into() });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new_spanned(
|
|
||||||
&nv.lit,
|
|
||||||
"Value must be string literal",
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
} else {
|
// why moved ? Want to use it in error
|
||||||
return Err(
|
match &args.nested[0] {
|
||||||
Error::new_spanned(attr, "Invalid property for guard").into()
|
NestedMeta::Meta(rule) => {
|
||||||
);
|
println! ("rule sended = {:#?}\n", rule);
|
||||||
|
return generate_guards(crate_name, rule);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(Error::new_spanned(args, "Invalid guard (to be improve)").into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"and" => {
|
||||||
|
println!("ident and found {:#?}\n", ident);
|
||||||
|
return Err(Error::new_spanned(args, "WIP").into());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let mut guards = None;
|
||||||
|
//args == "guard"
|
||||||
|
println!("items = {:#?}\n", &args.nested);
|
||||||
|
let ty = &args.path;
|
||||||
|
//ty = the rule
|
||||||
|
println!("ty = {:#?}\n", ty);
|
||||||
|
let mut params = Vec::new();
|
||||||
|
//rules params
|
||||||
|
for attr in &args.nested {
|
||||||
|
if let NestedMeta::Meta(Meta::NameValue(nv)) = attr {
|
||||||
|
let name = &nv.path;
|
||||||
|
if let Lit::Str(value) = &nv.lit {
|
||||||
|
let value_str = value.value();
|
||||||
|
if value_str.starts_with('@') {
|
||||||
|
let getter_name = get_param_getter_ident(&value_str[1..]);
|
||||||
|
params.push(quote! { #name: #getter_name()? });
|
||||||
|
} else {
|
||||||
|
let expr = syn::parse_str::<Expr>(&value_str)?;
|
||||||
|
params.push(quote! { #name: (#expr).into() });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(Error::new_spanned(
|
||||||
|
&nv.lit,
|
||||||
|
"Value must be string literal",
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(
|
||||||
|
Error::new_spanned(attr, "Invalid property for guard").into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let guard = quote! { #ty { #(#params),* } };
|
||||||
|
if guards.is_none() {
|
||||||
|
guards = Some(guard);
|
||||||
|
} else {
|
||||||
|
guards =
|
||||||
|
Some(quote! { #crate_name::guard::GuardExt::and(#guard, #guards) });
|
||||||
|
}
|
||||||
|
println!("end of function");
|
||||||
|
Ok(guards)
|
||||||
|
//return Err(Error::new_spanned(ident, "Invalid guard (to be improve 2)").into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let guard = quote! { #ty { #(#params),* } };
|
},
|
||||||
if guards.is_none() {
|
None => {
|
||||||
guards = Some(guard);
|
println!("failed for the moment");
|
||||||
} else {
|
return Err(Error::new_spanned(args, "WIP").into());
|
||||||
guards =
|
|
||||||
Some(quote! { #crate_name::guard::GuardExt::and(#guard, #guards) });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new_spanned(item, "Invalid guard").into());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(guards)
|
|
||||||
}
|
}
|
||||||
_ => Err(Error::new_spanned(args, "Invalid guards").into()),
|
_ => Err(Error::new_spanned(args, "Invalid guards (old)").into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
223
tests/guard.rs
223
tests/guard.rs
|
@ -40,137 +40,21 @@ impl Guard for UserGuard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
|
||||||
pub async fn test_guard() {
|
|
||||||
#[derive(SimpleObject)]
|
|
||||||
struct MyObj {
|
|
||||||
#[graphql(guard(RoleGuard(role = "Role::Admin")))]
|
|
||||||
value: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Query;
|
|
||||||
|
|
||||||
#[Object]
|
|
||||||
impl Query {
|
|
||||||
#[graphql(guard(RoleGuard(role = "Role::Admin")))]
|
|
||||||
async fn value(&self) -> i32 {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn obj(&self) -> MyObj {
|
|
||||||
MyObj { value: 99 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Subscription;
|
|
||||||
|
|
||||||
#[Subscription]
|
|
||||||
impl Subscription {
|
|
||||||
#[graphql(guard(RoleGuard(role = "Role::Admin")))]
|
|
||||||
async fn values(&self) -> impl Stream<Item = i32> {
|
|
||||||
futures::stream::iter(vec![1, 2, 3])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let schema = Schema::new(Query, EmptyMutation, Subscription);
|
|
||||||
|
|
||||||
let query = "{ obj { value } }";
|
|
||||||
assert_eq!(
|
|
||||||
schema
|
|
||||||
.execute(Request::new(query).data(Role::Admin))
|
|
||||||
.await
|
|
||||||
.data,
|
|
||||||
serde_json::json!({
|
|
||||||
"obj": {"value": 99}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
let query = "{ obj { value } }";
|
|
||||||
assert_eq!(
|
|
||||||
schema
|
|
||||||
.execute(Request::new(query).data(Role::Guest))
|
|
||||||
.await
|
|
||||||
.into_result()
|
|
||||||
.unwrap_err(),
|
|
||||||
vec![ServerError {
|
|
||||||
message: "Forbidden".to_owned(),
|
|
||||||
locations: vec![Pos { line: 1, column: 9 }],
|
|
||||||
path: vec![
|
|
||||||
PathSegment::Field("obj".to_owned()),
|
|
||||||
PathSegment::Field("value".to_owned())
|
|
||||||
],
|
|
||||||
extensions: None,
|
|
||||||
}]
|
|
||||||
);
|
|
||||||
|
|
||||||
let query = "{ value }";
|
|
||||||
assert_eq!(
|
|
||||||
schema
|
|
||||||
.execute(Request::new(query).data(Role::Admin))
|
|
||||||
.await
|
|
||||||
.data,
|
|
||||||
serde_json::json!({
|
|
||||||
"value": 1,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
let query = "{ value }";
|
|
||||||
assert_eq!(
|
|
||||||
schema
|
|
||||||
.execute(Request::new(query).data(Role::Guest))
|
|
||||||
.await
|
|
||||||
.into_result()
|
|
||||||
.unwrap_err(),
|
|
||||||
vec![ServerError {
|
|
||||||
message: "Forbidden".to_string(),
|
|
||||||
locations: vec![Pos { line: 1, column: 3 }],
|
|
||||||
path: vec![PathSegment::Field("value".to_owned())],
|
|
||||||
extensions: None,
|
|
||||||
}]
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
schema
|
|
||||||
.execute_stream(Request::new("subscription { values }").data(Role::Admin))
|
|
||||||
.map(|item| item.data)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.await,
|
|
||||||
vec![
|
|
||||||
serde_json::json! ({"values": 1}),
|
|
||||||
serde_json::json! ({"values": 2}),
|
|
||||||
serde_json::json! ({"values": 3})
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
schema
|
|
||||||
.execute_stream(Request::new("subscription { values }").data(Role::Guest))
|
|
||||||
.boxed()
|
|
||||||
.next()
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.errors,
|
|
||||||
vec![ServerError {
|
|
||||||
message: "Forbidden".to_string(),
|
|
||||||
locations: vec![Pos {
|
|
||||||
line: 1,
|
|
||||||
column: 16
|
|
||||||
}],
|
|
||||||
path: vec![PathSegment::Field("values".to_owned())],
|
|
||||||
extensions: None,
|
|
||||||
}]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
pub async fn test_multiple_guards() {
|
pub async fn test_multiple_guards() {
|
||||||
#[derive(SimpleObject)]
|
#[derive(SimpleObject)]
|
||||||
struct Query {
|
struct Query {
|
||||||
#[graphql(guard(RoleGuard(role = "Role::Admin"), UserGuard(username = r#""test""#)))]
|
#[graphql(guard(RoleGuard(role = "Role::Admin")))]
|
||||||
value: i32,
|
value: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
let schema = Schema::new(Query { value: 10 }, EmptyMutation, EmptySubscription);
|
#[derive(SimpleObject)]
|
||||||
|
struct Mutation {
|
||||||
|
value: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let schema = Schema::new(Query { value: 10 }, Mutation {value: 11}, EmptySubscription);
|
||||||
|
|
||||||
let query = "{ value }";
|
let query = "{ value }";
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -204,95 +88,4 @@ pub async fn test_multiple_guards() {
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
|
|
||||||
let query = "{ value }";
|
|
||||||
assert_eq!(
|
|
||||||
schema
|
|
||||||
.execute(
|
|
||||||
Request::new(query)
|
|
||||||
.data(Role::Admin)
|
|
||||||
.data(Username("test1".to_string()))
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.into_result()
|
|
||||||
.unwrap_err(),
|
|
||||||
vec![ServerError {
|
|
||||||
message: "Forbidden".to_string(),
|
|
||||||
locations: vec![Pos { line: 1, column: 3 }],
|
|
||||||
path: vec![PathSegment::Field("value".to_owned())],
|
|
||||||
extensions: None,
|
|
||||||
}]
|
|
||||||
);
|
|
||||||
|
|
||||||
let query = "{ value }";
|
|
||||||
assert_eq!(
|
|
||||||
schema
|
|
||||||
.execute(
|
|
||||||
Request::new(query)
|
|
||||||
.data(Role::Guest)
|
|
||||||
.data(Username("test1".to_string()))
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.into_result()
|
|
||||||
.unwrap_err(),
|
|
||||||
vec![ServerError {
|
|
||||||
message: "Forbidden".to_string(),
|
|
||||||
locations: vec![Pos { line: 1, column: 3 }],
|
|
||||||
path: vec![PathSegment::Field("value".to_owned())],
|
|
||||||
extensions: None,
|
|
||||||
}]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_std::test]
|
|
||||||
pub async fn test_guard_forward_arguments() {
|
|
||||||
struct UserGuard {
|
|
||||||
id: ID,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Guard for UserGuard {
|
|
||||||
async fn check(&self, ctx: &Context<'_>) -> Result<()> {
|
|
||||||
if ctx.data_opt::<ID>() != Some(&self.id) {
|
|
||||||
Err("Forbidden".into())
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct QueryRoot;
|
|
||||||
|
|
||||||
#[Object]
|
|
||||||
impl QueryRoot {
|
|
||||||
#[graphql(guard(UserGuard(id = "@id")))]
|
|
||||||
async fn user(&self, id: ID) -> ID {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let schema = Schema::new(QueryRoot, EmptyMutation, EmptySubscription);
|
|
||||||
|
|
||||||
let query = r#"{ user(id: "abc") }"#;
|
|
||||||
assert_eq!(
|
|
||||||
schema
|
|
||||||
.execute(Request::new(query).data(ID::from("abc")))
|
|
||||||
.await
|
|
||||||
.data,
|
|
||||||
serde_json::json!({"user": "abc"})
|
|
||||||
);
|
|
||||||
|
|
||||||
let query = r#"{ user(id: "abc") }"#;
|
|
||||||
assert_eq!(
|
|
||||||
schema
|
|
||||||
.execute(Request::new(query).data(ID::from("aaa")))
|
|
||||||
.await
|
|
||||||
.into_result()
|
|
||||||
.unwrap_err(),
|
|
||||||
vec![ServerError {
|
|
||||||
message: "Forbidden".to_string(),
|
|
||||||
locations: vec![Pos { line: 1, column: 3 }],
|
|
||||||
path: vec![PathSegment::Field("user".to_owned())],
|
|
||||||
extensions: None,
|
|
||||||
}]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user