mirror of
https://github.com/lldap/lldap.git
synced 2026-07-25 17:58:44 +00:00
server: Add the attribute schema to the attributes in graphql
And make sure that we only request the schema once per top-level query
This commit is contained in:
committed by
nitnelave
parent
1f2f034a48
commit
e308a5e9a1
Generated
+5
-4
@@ -1,6 +1,7 @@
|
|||||||
type AttributeValue {
|
type AttributeValue {
|
||||||
name: String!
|
name: String!
|
||||||
value: [String!]!
|
value: [String!]!
|
||||||
|
schema: AttributeSchema!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
@@ -152,10 +153,6 @@ type User {
|
|||||||
groups: [Group!]!
|
groups: [Group!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type AttributeList {
|
|
||||||
attributes: [AttributeSchema!]!
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AttributeType {
|
enum AttributeType {
|
||||||
STRING
|
STRING
|
||||||
INTEGER
|
INTEGER
|
||||||
@@ -163,6 +160,10 @@ enum AttributeType {
|
|||||||
DATE_TIME
|
DATE_TIME
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AttributeList {
|
||||||
|
attributes: [AttributeSchema!]!
|
||||||
|
}
|
||||||
|
|
||||||
type Success {
|
type Success {
|
||||||
ok: Boolean!
|
ok: Boolean!
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::domain::{
|
|||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize)]
|
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct PublicSchema(Schema);
|
pub struct PublicSchema(Schema);
|
||||||
|
|
||||||
impl PublicSchema {
|
impl PublicSchema {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
domain::{
|
domain::{
|
||||||
deserialize::deserialize_attribute_value,
|
deserialize::deserialize_attribute_value,
|
||||||
@@ -159,11 +161,8 @@ impl<Handler: BackendHandler> Mutation<Handler> {
|
|||||||
})
|
})
|
||||||
.instrument(span.clone())
|
.instrument(span.clone())
|
||||||
.await?;
|
.await?;
|
||||||
Ok(handler
|
let user_details = handler.get_user_details(&user_id).instrument(span).await?;
|
||||||
.get_user_details(&user_id)
|
super::query::User::<Handler>::from_user(user_details, Arc::new(schema))
|
||||||
.instrument(span)
|
|
||||||
.await
|
|
||||||
.map(Into::into)?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_group(
|
async fn create_group(
|
||||||
@@ -513,11 +512,8 @@ async fn create_group_with_details<Handler: BackendHandler>(
|
|||||||
attributes,
|
attributes,
|
||||||
};
|
};
|
||||||
let group_id = handler.create_group(request).await?;
|
let group_id = handler.create_group(request).await?;
|
||||||
Ok(handler
|
let group_details = handler.get_group_details(group_id).instrument(span).await?;
|
||||||
.get_group_details(group_id)
|
super::query::Group::<Handler>::from_group_details(group_details, Arc::new(schema))
|
||||||
.instrument(span)
|
|
||||||
.await
|
|
||||||
.map(Into::into)?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_attribute(
|
fn deserialize_attribute(
|
||||||
|
|||||||
+217
-166
@@ -1,13 +1,12 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
domain::{
|
domain::{
|
||||||
deserialize::deserialize_attribute_value,
|
deserialize::deserialize_attribute_value,
|
||||||
handler::{BackendHandler, ReadSchemaBackendHandler},
|
handler::{BackendHandler, ReadSchemaBackendHandler},
|
||||||
ldap::utils::{map_user_field, UserFieldType},
|
ldap::utils::{map_user_field, UserFieldType},
|
||||||
model::UserColumn,
|
model::UserColumn,
|
||||||
schema::{
|
schema::PublicSchema,
|
||||||
PublicSchema, SchemaAttributeExtractor, SchemaGroupAttributeExtractor,
|
|
||||||
SchemaUserAttributeExtractor,
|
|
||||||
},
|
|
||||||
types::{AttributeType, GroupDetails, GroupId, JpegPhoto, UserId},
|
types::{AttributeType, GroupDetails, GroupId, JpegPhoto, UserId},
|
||||||
},
|
},
|
||||||
infra::{
|
infra::{
|
||||||
@@ -143,11 +142,9 @@ impl<Handler: BackendHandler> Query<Handler> {
|
|||||||
&span,
|
&span,
|
||||||
"Unauthorized access to user data",
|
"Unauthorized access to user data",
|
||||||
))?;
|
))?;
|
||||||
Ok(handler
|
let schema = Arc::new(self.get_schema(context, span.clone()).await?);
|
||||||
.get_user_details(&user_id)
|
let user = handler.get_user_details(&user_id).instrument(span).await?;
|
||||||
.instrument(span)
|
User::<Handler>::from_user(user, schema)
|
||||||
.await
|
|
||||||
.map(Into::into)?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn users(
|
async fn users(
|
||||||
@@ -164,8 +161,8 @@ impl<Handler: BackendHandler> Query<Handler> {
|
|||||||
&span,
|
&span,
|
||||||
"Unauthorized access to user list",
|
"Unauthorized access to user list",
|
||||||
))?;
|
))?;
|
||||||
let schema = self.get_schema(context, span.clone()).await?;
|
let schema = Arc::new(self.get_schema(context, span.clone()).await?);
|
||||||
Ok(handler
|
let users = handler
|
||||||
.list_users(
|
.list_users(
|
||||||
filters
|
filters
|
||||||
.map(|f| f.try_into_domain_filter(&schema))
|
.map(|f| f.try_into_domain_filter(&schema))
|
||||||
@@ -173,8 +170,11 @@ impl<Handler: BackendHandler> Query<Handler> {
|
|||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
.instrument(span)
|
.instrument(span)
|
||||||
.await
|
.await?;
|
||||||
.map(|v| v.into_iter().map(Into::into).collect())?)
|
users
|
||||||
|
.into_iter()
|
||||||
|
.map(|u| User::<Handler>::from_user_and_groups(u, schema.clone()))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn groups(context: &Context<Handler>) -> FieldResult<Vec<Group<Handler>>> {
|
async fn groups(context: &Context<Handler>) -> FieldResult<Vec<Group<Handler>>> {
|
||||||
@@ -185,11 +185,12 @@ impl<Handler: BackendHandler> Query<Handler> {
|
|||||||
&span,
|
&span,
|
||||||
"Unauthorized access to group list",
|
"Unauthorized access to group list",
|
||||||
))?;
|
))?;
|
||||||
Ok(handler
|
let schema = Arc::new(self.get_schema(context, span.clone()).await?);
|
||||||
.list_groups(None)
|
let domain_groups = handler.list_groups(None).instrument(span).await?;
|
||||||
.instrument(span)
|
domain_groups
|
||||||
.await
|
.into_iter()
|
||||||
.map(|v| v.into_iter().map(Into::into).collect())?)
|
.map(|g| Group::<Handler>::from_group(g, schema.clone()))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn group(context: &Context<Handler>, group_id: i32) -> FieldResult<Group<Handler>> {
|
async fn group(context: &Context<Handler>, group_id: i32) -> FieldResult<Group<Handler>> {
|
||||||
@@ -203,11 +204,12 @@ impl<Handler: BackendHandler> Query<Handler> {
|
|||||||
&span,
|
&span,
|
||||||
"Unauthorized access to group data",
|
"Unauthorized access to group data",
|
||||||
))?;
|
))?;
|
||||||
Ok(handler
|
let schema = Arc::new(self.get_schema(context, span.clone()).await?);
|
||||||
|
let group_details = handler
|
||||||
.get_group_details(GroupId(group_id))
|
.get_group_details(GroupId(group_id))
|
||||||
.instrument(span)
|
.instrument(span)
|
||||||
.await
|
.await?;
|
||||||
.map(Into::into)?)
|
Group::<Handler>::from_group_details(group_details, schema.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn schema(context: &Context<Handler>) -> FieldResult<Schema<Handler>> {
|
async fn schema(context: &Context<Handler>) -> FieldResult<Schema<Handler>> {
|
||||||
@@ -237,16 +239,45 @@ impl<Handler: BackendHandler> Query<Handler> {
|
|||||||
/// Represents a single user.
|
/// Represents a single user.
|
||||||
pub struct User<Handler: BackendHandler> {
|
pub struct User<Handler: BackendHandler> {
|
||||||
user: DomainUser,
|
user: DomainUser,
|
||||||
|
attributes: Vec<AttributeValue<Handler>>,
|
||||||
|
schema: Arc<PublicSchema>,
|
||||||
|
groups: Option<Vec<Group<Handler>>>,
|
||||||
_phantom: std::marker::PhantomData<Box<Handler>>,
|
_phantom: std::marker::PhantomData<Box<Handler>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
impl<Handler: BackendHandler> User<Handler> {
|
||||||
impl<Handler: BackendHandler> Default for User<Handler> {
|
pub fn from_user(mut user: DomainUser, schema: Arc<PublicSchema>) -> FieldResult<Self> {
|
||||||
fn default() -> Self {
|
let attributes = std::mem::take(&mut user.attributes);
|
||||||
Self {
|
Ok(Self {
|
||||||
user: DomainUser::default(),
|
user,
|
||||||
|
attributes: attributes
|
||||||
|
.into_iter()
|
||||||
|
.map(|a| {
|
||||||
|
AttributeValue::<Handler>::from_schema(a, &schema.get_schema().user_attributes)
|
||||||
|
})
|
||||||
|
.collect::<FieldResult<Vec<_>>>()?,
|
||||||
|
schema,
|
||||||
|
groups: None,
|
||||||
_phantom: std::marker::PhantomData,
|
_phantom: std::marker::PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Handler: BackendHandler> User<Handler> {
|
||||||
|
pub fn from_user_and_groups(
|
||||||
|
DomainUserAndGroups { user, groups }: DomainUserAndGroups,
|
||||||
|
schema: Arc<PublicSchema>,
|
||||||
|
) -> FieldResult<Self> {
|
||||||
|
let mut user = Self::from_user(user, schema.clone())?;
|
||||||
|
if let Some(groups) = groups {
|
||||||
|
user.groups = Some(
|
||||||
|
groups
|
||||||
|
.into_iter()
|
||||||
|
.map(|g| Group::<Handler>::from_group_details(g, schema.clone()))
|
||||||
|
.collect::<FieldResult<Vec<_>>>()?,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Ok(user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,17 +330,15 @@ impl<Handler: BackendHandler> User<Handler> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// User-defined attributes.
|
/// User-defined attributes.
|
||||||
fn attributes(&self) -> Vec<AttributeValue<Handler, SchemaUserAttributeExtractor>> {
|
fn attributes(&self) -> &[AttributeValue<Handler>] {
|
||||||
self.user
|
&self.attributes
|
||||||
.attributes
|
|
||||||
.clone()
|
|
||||||
.into_iter()
|
|
||||||
.map(Into::into)
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The groups to which this user belongs.
|
/// The groups to which this user belongs.
|
||||||
async fn groups(&self, context: &Context<Handler>) -> FieldResult<Vec<Group<Handler>>> {
|
async fn groups(&self, context: &Context<Handler>) -> FieldResult<Vec<Group<Handler>>> {
|
||||||
|
if let Some(groups) = &self.groups {
|
||||||
|
return Ok(groups.clone());
|
||||||
|
}
|
||||||
let span = debug_span!("[GraphQL query] user::groups");
|
let span = debug_span!("[GraphQL query] user::groups");
|
||||||
span.in_scope(|| {
|
span.in_scope(|| {
|
||||||
debug!(user_id = ?self.user.user_id);
|
debug!(user_id = ?self.user.user_id);
|
||||||
@@ -317,36 +346,16 @@ impl<Handler: BackendHandler> User<Handler> {
|
|||||||
let handler = context
|
let handler = context
|
||||||
.get_readable_handler(&self.user.user_id)
|
.get_readable_handler(&self.user.user_id)
|
||||||
.expect("We shouldn't be able to get there without readable permission");
|
.expect("We shouldn't be able to get there without readable permission");
|
||||||
Ok(handler
|
let domain_groups = handler
|
||||||
.get_user_groups(&self.user.user_id)
|
.get_user_groups(&self.user.user_id)
|
||||||
.instrument(span)
|
.instrument(span)
|
||||||
.await
|
.await?;
|
||||||
.map(|set| {
|
let mut groups = domain_groups
|
||||||
let mut groups = set
|
.into_iter()
|
||||||
.into_iter()
|
.map(|g| Group::<Handler>::from_group_details(g, self.schema.clone()))
|
||||||
.map(Into::into)
|
.collect::<FieldResult<Vec<Group<Handler>>>>()?;
|
||||||
.collect::<Vec<Group<Handler>>>();
|
groups.sort_by(|g1, g2| g1.display_name.cmp(&g2.display_name));
|
||||||
groups.sort_by(|g1, g2| g1.display_name.cmp(&g2.display_name));
|
Ok(groups)
|
||||||
groups
|
|
||||||
})?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Handler: BackendHandler> From<DomainUser> for User<Handler> {
|
|
||||||
fn from(user: DomainUser) -> Self {
|
|
||||||
Self {
|
|
||||||
user,
|
|
||||||
_phantom: std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Handler: BackendHandler> From<DomainUserAndGroups> for User<Handler> {
|
|
||||||
fn from(user: DomainUserAndGroups) -> Self {
|
|
||||||
Self {
|
|
||||||
user: user.user,
|
|
||||||
_phantom: std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,11 +366,69 @@ pub struct Group<Handler: BackendHandler> {
|
|||||||
display_name: String,
|
display_name: String,
|
||||||
creation_date: chrono::NaiveDateTime,
|
creation_date: chrono::NaiveDateTime,
|
||||||
uuid: String,
|
uuid: String,
|
||||||
attributes: Vec<DomainAttributeValue>,
|
attributes: Vec<AttributeValue<Handler>>,
|
||||||
members: Option<Vec<String>>,
|
schema: Arc<PublicSchema>,
|
||||||
_phantom: std::marker::PhantomData<Box<Handler>>,
|
_phantom: std::marker::PhantomData<Box<Handler>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Handler: BackendHandler> Group<Handler> {
|
||||||
|
pub fn from_group(
|
||||||
|
group: DomainGroup,
|
||||||
|
schema: Arc<PublicSchema>,
|
||||||
|
) -> FieldResult<Group<Handler>> {
|
||||||
|
Ok(Self {
|
||||||
|
group_id: group.id.0,
|
||||||
|
display_name: group.display_name.to_string(),
|
||||||
|
creation_date: group.creation_date,
|
||||||
|
uuid: group.uuid.into_string(),
|
||||||
|
attributes: group
|
||||||
|
.attributes
|
||||||
|
.into_iter()
|
||||||
|
.map(|a| {
|
||||||
|
AttributeValue::<Handler>::from_schema(a, &schema.get_schema().group_attributes)
|
||||||
|
})
|
||||||
|
.collect::<FieldResult<Vec<_>>>()?,
|
||||||
|
schema,
|
||||||
|
_phantom: std::marker::PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_group_details(
|
||||||
|
group_details: GroupDetails,
|
||||||
|
schema: Arc<PublicSchema>,
|
||||||
|
) -> FieldResult<Group<Handler>> {
|
||||||
|
Ok(Self {
|
||||||
|
group_id: group_details.group_id.0,
|
||||||
|
display_name: group_details.display_name.to_string(),
|
||||||
|
creation_date: group_details.creation_date,
|
||||||
|
uuid: group_details.uuid.into_string(),
|
||||||
|
attributes: group_details
|
||||||
|
.attributes
|
||||||
|
.into_iter()
|
||||||
|
.map(|a| {
|
||||||
|
AttributeValue::<Handler>::from_schema(a, &schema.get_schema().group_attributes)
|
||||||
|
})
|
||||||
|
.collect::<FieldResult<Vec<_>>>()?,
|
||||||
|
schema,
|
||||||
|
_phantom: std::marker::PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Handler: BackendHandler> Clone for Group<Handler> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
group_id: self.group_id,
|
||||||
|
display_name: self.display_name.clone(),
|
||||||
|
creation_date: self.creation_date,
|
||||||
|
uuid: self.uuid.clone(),
|
||||||
|
attributes: self.attributes.clone(),
|
||||||
|
schema: self.schema.clone(),
|
||||||
|
_phantom: std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[graphql_object(context = Context<Handler>)]
|
#[graphql_object(context = Context<Handler>)]
|
||||||
impl<Handler: BackendHandler> Group<Handler> {
|
impl<Handler: BackendHandler> Group<Handler> {
|
||||||
fn id(&self) -> i32 {
|
fn id(&self) -> i32 {
|
||||||
@@ -378,12 +445,8 @@ impl<Handler: BackendHandler> Group<Handler> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// User-defined attributes.
|
/// User-defined attributes.
|
||||||
fn attributes(&self) -> Vec<AttributeValue<Handler, SchemaGroupAttributeExtractor>> {
|
fn attributes(&self) -> &[AttributeValue<Handler>] {
|
||||||
self.attributes
|
&self.attributes
|
||||||
.clone()
|
|
||||||
.into_iter()
|
|
||||||
.map(Into::into)
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The groups to which this user belongs.
|
/// The groups to which this user belongs.
|
||||||
@@ -398,42 +461,17 @@ impl<Handler: BackendHandler> Group<Handler> {
|
|||||||
&span,
|
&span,
|
||||||
"Unauthorized access to group data",
|
"Unauthorized access to group data",
|
||||||
))?;
|
))?;
|
||||||
Ok(handler
|
let domain_users = handler
|
||||||
.list_users(
|
.list_users(
|
||||||
Some(DomainRequestFilter::MemberOfId(GroupId(self.group_id))),
|
Some(DomainRequestFilter::MemberOfId(GroupId(self.group_id))),
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
.instrument(span)
|
.instrument(span)
|
||||||
.await
|
.await?;
|
||||||
.map(|v| v.into_iter().map(Into::into).collect())?)
|
domain_users
|
||||||
}
|
.into_iter()
|
||||||
}
|
.map(|u| User::<Handler>::from_user_and_groups(u, self.schema.clone()))
|
||||||
|
.collect()
|
||||||
impl<Handler: BackendHandler> From<GroupDetails> for Group<Handler> {
|
|
||||||
fn from(group_details: GroupDetails) -> Self {
|
|
||||||
Self {
|
|
||||||
group_id: group_details.group_id.0,
|
|
||||||
display_name: group_details.display_name.to_string(),
|
|
||||||
creation_date: group_details.creation_date,
|
|
||||||
uuid: group_details.uuid.into_string(),
|
|
||||||
attributes: group_details.attributes,
|
|
||||||
members: None,
|
|
||||||
_phantom: std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Handler: BackendHandler> From<DomainGroup> for Group<Handler> {
|
|
||||||
fn from(group: DomainGroup) -> Self {
|
|
||||||
Self {
|
|
||||||
group_id: group.id.0,
|
|
||||||
display_name: group.display_name.to_string(),
|
|
||||||
creation_date: group.creation_date,
|
|
||||||
uuid: group.uuid.into_string(),
|
|
||||||
attributes: group.attributes,
|
|
||||||
members: Some(group.users.into_iter().map(UserId::into_string).collect()),
|
|
||||||
_phantom: std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,6 +503,15 @@ impl<Handler: BackendHandler> AttributeSchema<Handler> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Handler: BackendHandler> Clone for AttributeSchema<Handler> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
schema: self.schema.clone(),
|
||||||
|
_phantom: std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<Handler: BackendHandler> From<DomainAttributeSchema> for AttributeSchema<Handler> {
|
impl<Handler: BackendHandler> From<DomainAttributeSchema> for AttributeSchema<Handler> {
|
||||||
fn from(value: DomainAttributeSchema) -> Self {
|
fn from(value: DomainAttributeSchema) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -527,88 +574,92 @@ impl<Handler: BackendHandler> From<PublicSchema> for Schema<Handler> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize)]
|
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||||
pub struct AttributeValue<Handler: BackendHandler, Extractor> {
|
pub struct AttributeValue<Handler: BackendHandler> {
|
||||||
attribute: DomainAttributeValue,
|
attribute: DomainAttributeValue,
|
||||||
|
schema: AttributeSchema<Handler>,
|
||||||
_phantom: std::marker::PhantomData<Box<Handler>>,
|
_phantom: std::marker::PhantomData<Box<Handler>>,
|
||||||
_phantom_extractor: std::marker::PhantomData<Extractor>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[graphql_object(context = Context<Handler>)]
|
#[graphql_object(context = Context<Handler>)]
|
||||||
impl<Handler: BackendHandler, Extractor: SchemaAttributeExtractor>
|
impl<Handler: BackendHandler> AttributeValue<Handler> {
|
||||||
AttributeValue<Handler, Extractor>
|
|
||||||
{
|
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
self.attribute.name.as_str()
|
self.attribute.name.as_str()
|
||||||
}
|
}
|
||||||
async fn value(&self, context: &Context<Handler>) -> FieldResult<Vec<String>> {
|
|
||||||
let handler = context
|
fn value(&self) -> FieldResult<Vec<String>> {
|
||||||
.handler
|
Ok(serialize_attribute(&self.attribute, &self.schema.schema))
|
||||||
.get_user_restricted_lister_handler(&context.validation_result);
|
}
|
||||||
serialize_attribute(
|
|
||||||
&self.attribute,
|
fn schema(&self) -> &AttributeSchema<Handler> {
|
||||||
Extractor::get_attributes(&PublicSchema::from(handler.get_schema().await?)),
|
&self.schema
|
||||||
)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Handler: BackendHandler> Clone for AttributeValue<Handler> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
attribute: self.attribute.clone(),
|
||||||
|
schema: self.schema.clone(),
|
||||||
|
_phantom: std::marker::PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize_attribute(
|
pub fn serialize_attribute(
|
||||||
attribute: &DomainAttributeValue,
|
attribute: &DomainAttributeValue,
|
||||||
attributes: &DomainAttributeList,
|
attribute_schema: &DomainAttributeSchema,
|
||||||
) -> FieldResult<Vec<String>> {
|
) -> Vec<String> {
|
||||||
let convert_date = |date| chrono::Utc.from_utc_datetime(&date).to_rfc3339();
|
let convert_date = |date| chrono::Utc.from_utc_datetime(&date).to_rfc3339();
|
||||||
attributes
|
match (attribute_schema.attribute_type, attribute_schema.is_list) {
|
||||||
.get_attribute_type(&attribute.name)
|
(AttributeType::String, false) => vec![attribute.value.unwrap::<String>()],
|
||||||
.map(|attribute_type| {
|
(AttributeType::Integer, false) => {
|
||||||
match attribute_type {
|
// LDAP integers are encoded as strings.
|
||||||
(AttributeType::String, false) => {
|
vec![attribute.value.unwrap::<i64>().to_string()]
|
||||||
vec![attribute.value.unwrap::<String>()]
|
}
|
||||||
}
|
(AttributeType::JpegPhoto, false) => {
|
||||||
(AttributeType::Integer, false) => {
|
vec![String::from(&attribute.value.unwrap::<JpegPhoto>())]
|
||||||
// LDAP integers are encoded as strings.
|
}
|
||||||
vec![attribute.value.unwrap::<i64>().to_string()]
|
(AttributeType::DateTime, false) => {
|
||||||
}
|
vec![convert_date(attribute.value.unwrap::<NaiveDateTime>())]
|
||||||
(AttributeType::JpegPhoto, false) => {
|
}
|
||||||
vec![String::from(&attribute.value.unwrap::<JpegPhoto>())]
|
(AttributeType::String, true) => attribute
|
||||||
}
|
.value
|
||||||
(AttributeType::DateTime, false) => {
|
.unwrap::<Vec<String>>()
|
||||||
vec![convert_date(attribute.value.unwrap::<NaiveDateTime>())]
|
.into_iter()
|
||||||
}
|
.collect(),
|
||||||
(AttributeType::String, true) => attribute
|
(AttributeType::Integer, true) => attribute
|
||||||
.value
|
.value
|
||||||
.unwrap::<Vec<String>>()
|
.unwrap::<Vec<i64>>()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect(),
|
.map(|i| i.to_string())
|
||||||
(AttributeType::Integer, true) => attribute
|
.collect(),
|
||||||
.value
|
(AttributeType::JpegPhoto, true) => attribute
|
||||||
.unwrap::<Vec<i64>>()
|
.value
|
||||||
.into_iter()
|
.unwrap::<Vec<JpegPhoto>>()
|
||||||
.map(|i| i.to_string())
|
.iter()
|
||||||
.collect(),
|
.map(String::from)
|
||||||
(AttributeType::JpegPhoto, true) => attribute
|
.collect(),
|
||||||
.value
|
(AttributeType::DateTime, true) => attribute
|
||||||
.unwrap::<Vec<JpegPhoto>>()
|
.value
|
||||||
.iter()
|
.unwrap::<Vec<NaiveDateTime>>()
|
||||||
.map(String::from)
|
.into_iter()
|
||||||
.collect(),
|
.map(convert_date)
|
||||||
(AttributeType::DateTime, true) => attribute
|
.collect(),
|
||||||
.value
|
}
|
||||||
.unwrap::<Vec<NaiveDateTime>>()
|
|
||||||
.into_iter()
|
|
||||||
.map(convert_date)
|
|
||||||
.collect(),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.ok_or_else(|| FieldError::from(anyhow::anyhow!("Unknown attribute: {}", &attribute.name)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Handler: BackendHandler, Extractor> From<DomainAttributeValue>
|
impl<Handler: BackendHandler> AttributeValue<Handler> {
|
||||||
for AttributeValue<Handler, Extractor>
|
fn from_schema(a: DomainAttributeValue, schema: &DomainAttributeList) -> FieldResult<Self> {
|
||||||
{
|
match schema.get_attribute_schema(&a.name) {
|
||||||
fn from(value: DomainAttributeValue) -> Self {
|
Some(s) => Ok(AttributeValue::<Handler> {
|
||||||
Self {
|
attribute: a,
|
||||||
attribute: value,
|
schema: AttributeSchema::<Handler> {
|
||||||
_phantom: std::marker::PhantomData,
|
schema: s.clone(),
|
||||||
_phantom_extractor: std::marker::PhantomData,
|
_phantom: std::marker::PhantomData,
|
||||||
|
},
|
||||||
|
_phantom: std::marker::PhantomData,
|
||||||
|
}),
|
||||||
|
None => Err(FieldError::from(format!("Unknown attribute {}", &a.name))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user