use crate::schema::Resource;
pub const ORGANIZATION_TOML: &str = r#"
[resource]
name = "organization"
scope = "global"
timestamps = true
[permissions]
list = "member" # organisations you belong to
read = "member"
create = "authenticated" # anyone may start one (and becomes its admin)
update = "role:admin" # an admin *of that organisation*
delete = "role:admin"
[fields.name]
type = "string"
required = true
[fields.slug]
type = "string"
unique = true
"#;
pub const MEMBERSHIP_TOML: &str = r#"
[resource]
name = "membership"
scope = "organization"
timestamps = true
[permissions]
list = "member" # members can see who else is in the org
read = "member"
create = "role:admin" # admins add members
update = "role:admin"
delete = "role:admin"
# Built-in function: lets `create` name the person by `email` instead of by
# `user_id`, and refuses a duplicate membership. The lookup has to happen here
# because `user` is only readable by people you already share an org with.
[hooks]
before_create = "apiplant_organization_join"
[fields.user_id]
type = "reference"
references = "user"
required = true
[fields.organization_id]
type = "reference"
references = "organization"
required = true
[fields.role]
type = "string" # the member's *primary* role here, e.g. "admin".
# Further roles are `membership_role` rows; a
# `role:` permission is checked against all of them.
"#;
pub const MEMBERSHIP_ROLE_TOML: &str = r#"
[resource]
name = "membership_role"
scope = "organization"
timestamps = true
[permissions]
list = "member" # members can see who holds what
read = "member"
create = "role:admin" # admins grant roles
update = "role:admin"
delete = "role:admin"
[fields.membership_id]
type = "reference"
references = "membership"
required = true
on_delete = "cascade" # a removed member takes their roles with them
[fields.organization_id]
type = "reference"
references = "organization"
required = true
[fields.role]
type = "string"
required = true
"#;
pub const USER_TOML: &str = r#"
[resource]
name = "user"
scope = "global"
timestamps = true
[permissions]
list = "member" # people you share an organisation with
read = "member"
create = "public" # registration
update = "owner"
delete = "private"
[auth]
identity_field = "email"
password_field = "password_hash"
oauth_providers = []
[fields.email]
type = "string"
required = true
unique = true
max_length = 320
[fields.password_hash]
type = "string"
hidden = true
[fields.display_name]
type = "string"
"#;
pub const API_KEY_TOML: &str = r#"
[resource]
name = "api_key"
scope = "global"
timestamps = true
# "Api key" is what titleising the name produces, and it is not how anybody
# writes it.
[admin]
label = "API key"
plural = "API keys"
[permissions]
list = "owner"
read = "owner"
create = "authenticated"
update = "private"
delete = "owner"
[fields.name]
type = "string"
[fields.token_hash]
type = "string"
required = true
unique = true
hidden = true
[fields.owner_id]
type = "reference"
references = "user"
required = true
"#;
pub const OAUTH_TOML: &str = r#"
[resource]
name = "oauth_connection"
scope = "global"
timestamps = true
[permissions]
list = "owner"
read = "owner"
create = "private"
update = "private"
delete = "owner"
[fields.provider]
type = "string"
required = true
[fields.provider_user_id]
type = "string"
required = true
[fields.owner_id]
type = "reference"
references = "user"
required = true
"#;
pub fn builtins() -> Vec<(&'static str, &'static str)> {
vec![
("organization", ORGANIZATION_TOML),
("user", USER_TOML),
("membership", MEMBERSHIP_TOML),
("membership_role", MEMBERSHIP_ROLE_TOML),
("api_key", API_KEY_TOML),
("oauth_connection", OAUTH_TOML),
]
}
pub fn parse_builtin(toml_src: &str) -> Resource {
let r: Resource = toml::from_str(toml_src).expect("built-in resource TOML is valid");
r.validate().expect("built-in resource is valid");
r
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn all_builtins_parse() {
for (name, src) in builtins() {
let r = parse_builtin(src);
assert_eq!(r.meta.name, name);
}
}
}