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 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
/// 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())
.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
.remove("protected")
.map(TryFrom::try_from)
@ -129,6 +141,7 @@ pub fn handle_method(mut attribs: JSONObject, mut func: syn::ItemFn) -> Result<T
#input_schema_name,
)
#returns_schema_setter
#access_setter
.protected(#protected);
#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 serde_json::{json, Value};
use proxmox::api::Permission;
#[api(
input: {
properties: {
@ -33,6 +35,10 @@ use serde_json::{json, Value};
},
},
},
access: {
description: "Only root can access this.",
permission: &Permission::Superuser,
},
protected: true,
)]
/// Create or verify authentication ticket.
@ -102,6 +108,7 @@ fn create_ticket_schema_check() {
)
.schema(),
)
.permissions("Only root can access this.", &Permission::Superuser)
.protected(true);
assert_eq!(TEST_METHOD, API_METHOD_CREATE_TICKET);
}