Skip to main content

cloudillo_core/
roles.rs

1//! Role hierarchy and expansion logic
2//!
3//! This module defines the built-in role hierarchy and provides utilities
4//! for expanding hierarchical roles.
5
6/// Role hierarchy for profile-level permissions
7/// Higher roles inherit all permissions from lower roles
8pub const ROLE_HIERARCHY: &[&str] =
9	&["public", "follower", "supporter", "contributor", "moderator", "leader"];
10
11/// Expands hierarchical roles from highest role to all inherited roles
12///
13/// Given a list of roles (typically just the highest one), this function
14/// returns a comma-separated string of all roles from "public" up to and
15/// including the highest role in the hierarchy.
16///
17/// # Examples
18/// ```
19/// use cloudillo_core::roles::expand_roles;
20/// assert_eq!(expand_roles(&["moderator".into()]), "public,follower,supporter,contributor,moderator");
21/// assert_eq!(expand_roles(&["contributor".into(), "moderator".into()]), "public,follower,supporter,contributor,moderator");
22/// assert_eq!(expand_roles(&[]), "");
23/// ```
24pub fn expand_roles(highest_roles: &[Box<str>]) -> String {
25	if highest_roles.is_empty() {
26		return String::new();
27	}
28
29	let mut highest_idx: Option<usize> = None;
30	for role in highest_roles {
31		if let Some(idx) = ROLE_HIERARCHY.iter().position(|&r| r == role.as_ref()) {
32			highest_idx = Some(highest_idx.map_or(idx, |h| h.max(idx)));
33		}
34	}
35
36	// Return comma-separated list of all roles up to highest, or empty if no valid roles found
37	match highest_idx {
38		Some(idx) => ROLE_HIERARCHY[..=idx].join(","),
39		None => String::new(),
40	}
41}
42
43#[cfg(test)]
44mod tests {
45	use super::*;
46
47	#[test]
48	fn test_expand_roles_empty() {
49		assert_eq!(expand_roles(&[]), "");
50	}
51
52	#[test]
53	fn test_expand_roles_single() {
54		assert_eq!(expand_roles(&["public".into()]), "public");
55		assert_eq!(expand_roles(&["follower".into()]), "public,follower");
56		assert_eq!(
57			expand_roles(&["moderator".into()]),
58			"public,follower,supporter,contributor,moderator"
59		);
60		assert_eq!(
61			expand_roles(&["leader".into()]),
62			"public,follower,supporter,contributor,moderator,leader"
63		);
64	}
65
66	#[test]
67	fn test_expand_roles_multiple() {
68		// Takes highest role
69		assert_eq!(
70			expand_roles(&["contributor".into(), "moderator".into()]),
71			"public,follower,supporter,contributor,moderator"
72		);
73		assert_eq!(
74			expand_roles(&["public".into(), "leader".into()]),
75			"public,follower,supporter,contributor,moderator,leader"
76		);
77	}
78
79	#[test]
80	fn test_expand_roles_unknown() {
81		// Unknown roles are ignored
82		assert_eq!(expand_roles(&["unknown".into()]), "");
83		assert_eq!(
84			expand_roles(&["unknown".into(), "contributor".into()]),
85			"public,follower,supporter,contributor"
86		);
87	}
88}
89
90// vim: ts=4