api-macro: support 'access' specification for methods

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2020-04-14 13:28:16 +02:00
parent 19ad65ac84
commit 510d410b7a
2 changed files with 65 additions and 1 deletions

View File

@ -17,7 +17,7 @@ use syn::Ident;
use syn::visit_mut::{self, VisitMut}; use syn::visit_mut::{self, VisitMut};
use super::{Schema, SchemaItem}; use super::{Schema, SchemaItem};
use crate::util::{self, FieldName, JSONObject}; use crate::util::{self, FieldName, JSONObject, JSONValue};
/// Parse `input`, `returns` and `protected` attributes out of an function annotated /// Parse `input`, `returns` and `protected` attributes out of an function annotated
/// with an `#[api]` attribute and produce a `const ApiMethod` named after the function. /// with an `#[api]` attribute and produce a `const ApiMethod` named after the function.
@ -39,6 +39,18 @@ pub fn handle_method(mut attribs: JSONObject, mut func: syn::ItemFn) -> Result<T
.map(|ret| ret.into_object("return schema definition")?.try_into()) .map(|ret| ret.into_object("return schema definition")?.try_into())
.transpose()?; .transpose()?;
let access_setter = match attribs.remove("access") {
Some(access) => {
let access = Access::try_from(access.into_object("access rules")?)?;
let description: syn::LitStr = access.description.try_into()?;
let permission: syn::Expr = access.permission.try_into()?;
quote_spanned! { access.span =>
.permissions(#description, #permission)
}
}
None => TokenStream::new(),
};
let protected: bool = attribs let protected: bool = attribs
.remove("protected") .remove("protected")
.map(TryFrom::try_from) .map(TryFrom::try_from)
@ -129,6 +141,7 @@ pub fn handle_method(mut attribs: JSONObject, mut func: syn::ItemFn) -> Result<T
#input_schema_name, #input_schema_name,
) )
#returns_schema_setter #returns_schema_setter
#access_setter
.protected(#protected); .protected(#protected);
#default_consts #default_consts
@ -510,3 +523,47 @@ impl<'a> DefaultParameters<'a> {
} }
} }
} }
struct Access {
span: Span,
description: syn::LitStr,
permission: syn::Expr,
}
impl TryFrom<JSONValue> for Access {
type Error = syn::Error;
fn try_from(value: JSONValue) -> Result<Self, syn::Error> {
Self::try_from(value.into_object("an access definition")?)
}
}
impl TryFrom<JSONObject> for Access {
type Error = syn::Error;
fn try_from(mut obj: JSONObject) -> Result<Self, syn::Error> {
let description = obj
.remove("description")
.ok_or_else(|| format_err!(obj.span(), "missing description"))?
.try_into()?;
let permission = obj
.remove("permission")
.ok_or_else(|| format_err!(obj.span(), "missing `permissions` field"))?
.try_into()?;
if !obj.is_empty() {
bail!(
obj.span(),
"unexpected elements: {}",
util::join_debug(", ", obj.elements.keys()),
);
}
Ok(Self {
span: obj.span(),
description,
permission,
})
}
}

View File

@ -3,6 +3,8 @@ use proxmox_api_macro::api;
use failure::Error; use failure::Error;
use serde_json::{json, Value}; use serde_json::{json, Value};
use proxmox::api::Permission;
#[api( #[api(
input: { input: {
properties: { properties: {
@ -33,6 +35,10 @@ use serde_json::{json, Value};
}, },
}, },
}, },
access: {
description: "Only root can access this.",
permission: &Permission::Superuser,
},
protected: true, protected: true,
)] )]
/// Create or verify authentication ticket. /// Create or verify authentication ticket.
@ -102,6 +108,7 @@ fn create_ticket_schema_check() {
) )
.schema(), .schema(),
) )
.permissions("Only root can access this.", &Permission::Superuser)
.protected(true); .protected(true);
assert_eq!(TEST_METHOD, API_METHOD_CREATE_TICKET); assert_eq!(TEST_METHOD, API_METHOD_CREATE_TICKET);
} }