use actix_http::{HttpMessage, StatusCode};
use actix_utils::future::{ready, Ready};
use actix_web::FromRequest;
use serde::Deserialize;
use uuid::Uuid;
use crate::error::ServiceError;
use super::claims::Claims;
#[derive(Debug, Clone, Deserialize)]
pub struct UserInfo {
pub id: Uuid,
pub scopes: Vec<String>,
pub roles: Vec<Role>,
}
#[derive(Debug, Clone, Deserialize)]
pub enum Role {
Member,
}
impl UserInfo {
#[must_use]
pub fn is_member(&self) -> bool {
self.roles.iter().any(|role| matches!(role, Role::Member))
}
}
impl Role {
#[must_use]
pub fn from_string(str: &str) -> Option<Self> {
match str {
"member" => Some(Self::Member),
_ => None,
}
}
}
impl From<Claims> for UserInfo {
fn from(value: Claims) -> Self {
let roles = match value.realm_access {
Some(realm_access) => realm_access
.roles
.into_iter()
.filter_map(|s| Role::from_string(&s))
.collect::<Vec<_>>(),
None => Vec::new(),
};
Self {
id: value.sub,
scopes: value.scope.split(' ').map(str::to_owned).collect(),
roles,
}
}
}
impl FromRequest for UserInfo {
type Future = Ready<Result<Self, Self::Error>>;
type Error = ServiceError;
fn from_request(
req: &actix_web::HttpRequest,
_payload: &mut actix_http::Payload,
) -> Self::Future {
let extensions = req.extensions();
ready({
extensions.get::<Self>().map_or_else(
|| {
Err(ServiceError::new(
StatusCode::INTERNAL_SERVER_ERROR,
&StatusCode::INTERNAL_SERVER_ERROR.to_string(),
))
},
|user_info| Ok(user_info.clone()),
)
})
}
}