use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use crate::role::{Permission, Role};
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct AuthUser {
pub id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub email: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub roles: Vec<Role>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub permissions: Vec<Permission>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub claims: BTreeMap<String, serde_json::Value>,
}
impl AuthUser {
pub fn new(id: impl Into<String>) -> Self {
Self {
id: id.into(),
email: None,
name: None,
roles: Vec::new(),
permissions: Vec::new(),
claims: BTreeMap::new(),
}
}
pub fn with_email(mut self, email: impl Into<String>) -> Self {
self.email = Some(email.into());
self
}
pub fn with_name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn with_role(mut self, role: Role) -> Self {
self.roles.push(role);
self
}
pub fn with_permission(mut self, permission: Permission) -> Self {
self.permissions.push(permission);
self
}
pub fn with_claim(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
self.claims.insert(key.into(), value);
self
}
pub fn has_role(&self, role: &Role) -> bool {
self.roles.iter().any(|candidate| candidate == role)
}
pub fn has_permission(&self, permission: &Permission) -> bool {
self.permissions
.iter()
.any(|candidate| candidate == permission)
}
pub fn claim(&self, key: &str) -> Option<&serde_json::Value> {
self.claims.get(key)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn auth_user_round_trips_arbitrary_claims() {
let user = AuthUser::new("uid-1")
.with_email("a@example.com")
.with_role(Role::admin())
.with_claim("firebase_uid", serde_json::json!("xyz"))
.with_claim("org_id", serde_json::json!(42));
let json = serde_json::to_string(&user).unwrap();
let round_tripped: AuthUser = serde_json::from_str(&json).unwrap();
assert_eq!(user, round_tripped);
assert_eq!(
round_tripped.claim("firebase_uid"),
Some(&serde_json::json!("xyz"))
);
assert_eq!(round_tripped.claim("org_id"), Some(&serde_json::json!(42)));
}
}