server: return user-defined attributes for groups in graphql
Part of #67
This commit is contained in:
committed by
nitnelave
parent
e53ce92c96
commit
034794d58d
@@ -1,7 +1,7 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::domain::types::{GroupId, Serialized};
|
||||
use crate::domain::types::{AttributeValue, GroupId, Serialized};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "group_attributes")]
|
||||
@@ -55,3 +55,18 @@ impl Related<super::GroupAttributeSchema> for Entity {
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
impl From<Model> for AttributeValue {
|
||||
fn from(
|
||||
Model {
|
||||
group_id: _,
|
||||
attribute_name,
|
||||
value,
|
||||
}: Model,
|
||||
) -> Self {
|
||||
Self {
|
||||
name: attribute_name,
|
||||
value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ impl From<Model> for crate::domain::types::Group {
|
||||
creation_date: group.creation_date,
|
||||
uuid: group.uuid,
|
||||
users: vec![],
|
||||
attributes: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,6 +49,7 @@ impl From<Model> for crate::domain::types::GroupDetails {
|
||||
display_name: group.display_name,
|
||||
creation_date: group.creation_date,
|
||||
uuid: group.uuid,
|
||||
attributes: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::domain::{
|
||||
},
|
||||
model::{self, GroupColumn, MembershipColumn},
|
||||
sql_backend_handler::SqlBackendHandler,
|
||||
types::{Group, GroupDetails, GroupId, Uuid},
|
||||
types::{AttributeValue, Group, GroupDetails, GroupId, Uuid},
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use sea_orm::{
|
||||
@@ -63,8 +63,7 @@ impl GroupListerBackendHandler for SqlBackendHandler {
|
||||
#[instrument(skip(self), level = "debug", ret, err)]
|
||||
async fn list_groups(&self, filters: Option<GroupRequestFilter>) -> Result<Vec<Group>> {
|
||||
let results = model::Group::find()
|
||||
// The order_by must be before find_with_related otherwise the primary order is by group_id.
|
||||
.order_by_asc(GroupColumn::DisplayName)
|
||||
.order_by_asc(GroupColumn::GroupId)
|
||||
.find_with_related(model::Membership)
|
||||
.filter(
|
||||
filters
|
||||
@@ -84,7 +83,7 @@ impl GroupListerBackendHandler for SqlBackendHandler {
|
||||
)
|
||||
.all(&self.sql_pool)
|
||||
.await?;
|
||||
Ok(results
|
||||
let mut groups: Vec<_> = results
|
||||
.into_iter()
|
||||
.map(|(group, users)| {
|
||||
let users: Vec<_> = users.into_iter().map(|u| u.user_id).collect();
|
||||
@@ -93,7 +92,30 @@ impl GroupListerBackendHandler for SqlBackendHandler {
|
||||
..group.into()
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
.collect();
|
||||
let group_ids = groups.iter().map(|u| &u.id);
|
||||
let attributes = model::GroupAttributes::find()
|
||||
.filter(model::GroupAttributesColumn::GroupId.is_in(group_ids))
|
||||
.order_by_asc(model::GroupAttributesColumn::GroupId)
|
||||
.order_by_asc(model::GroupAttributesColumn::AttributeName)
|
||||
.all(&self.sql_pool)
|
||||
.await?;
|
||||
let mut attributes_iter = attributes.into_iter().peekable();
|
||||
use itertools::Itertools; // For take_while_ref
|
||||
for group in groups.iter_mut() {
|
||||
assert!(attributes_iter
|
||||
.peek()
|
||||
.map(|u| u.group_id >= group.id)
|
||||
.unwrap_or(true),
|
||||
"Attributes are not sorted, groups are not sorted, or previous group didn't consume all the attributes");
|
||||
|
||||
group.attributes = attributes_iter
|
||||
.take_while_ref(|u| u.group_id == group.id)
|
||||
.map(AttributeValue::from)
|
||||
.collect();
|
||||
}
|
||||
groups.sort_by(|g1, g2| g1.display_name.cmp(&g2.display_name));
|
||||
Ok(groups)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,11 +123,18 @@ impl GroupListerBackendHandler for SqlBackendHandler {
|
||||
impl GroupBackendHandler for SqlBackendHandler {
|
||||
#[instrument(skip(self), level = "debug", ret, err)]
|
||||
async fn get_group_details(&self, group_id: GroupId) -> Result<GroupDetails> {
|
||||
model::Group::find_by_id(group_id)
|
||||
let mut group_details = model::Group::find_by_id(group_id)
|
||||
.one(&self.sql_pool)
|
||||
.await?
|
||||
.map(Into::<GroupDetails>::into)
|
||||
.ok_or_else(|| DomainError::EntityNotFound(format!("{:?}", group_id)))
|
||||
.ok_or_else(|| DomainError::EntityNotFound(format!("{:?}", group_id)))?;
|
||||
let attributes = model::GroupAttributes::find()
|
||||
.filter(model::GroupAttributesColumn::GroupId.eq(group_details.group_id))
|
||||
.order_by_asc(model::GroupAttributesColumn::AttributeName)
|
||||
.all(&self.sql_pool)
|
||||
.await?;
|
||||
group_details.attributes = attributes.into_iter().map(AttributeValue::from).collect();
|
||||
Ok(group_details)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug", err, fields(group_id = ?request.group_id))]
|
||||
|
||||
@@ -63,7 +63,7 @@ macro_rules! uuid {
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, DeriveValueType)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, DeriveValueType)]
|
||||
#[sea_orm(column_type = "Binary(BlobSize::Long)", array_type = "Bytes")]
|
||||
pub struct Serialized(Vec<u8>);
|
||||
|
||||
@@ -283,7 +283,7 @@ impl IntoActiveValue<Serialized> for JpegPhoto {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize, Hash)]
|
||||
pub struct AttributeValue {
|
||||
pub name: String,
|
||||
pub value: Serialized,
|
||||
@@ -314,7 +314,19 @@ impl Default for User {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, DeriveValueType)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Copy,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
DeriveValueType,
|
||||
)]
|
||||
pub struct GroupId(pub i32);
|
||||
|
||||
impl TryFromU64 for GroupId {
|
||||
@@ -323,6 +335,12 @@ impl TryFromU64 for GroupId {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&GroupId> for Value {
|
||||
fn from(id: &GroupId) -> Self {
|
||||
(*id).into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, EnumString, IntoStaticStr,
|
||||
)]
|
||||
@@ -375,6 +393,7 @@ pub struct Group {
|
||||
pub creation_date: NaiveDateTime,
|
||||
pub uuid: Uuid,
|
||||
pub users: Vec<UserId>,
|
||||
pub attributes: Vec<AttributeValue>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
@@ -383,6 +402,7 @@ pub struct GroupDetails {
|
||||
pub display_name: String,
|
||||
pub creation_date: NaiveDateTime,
|
||||
pub uuid: Uuid,
|
||||
pub attributes: Vec<AttributeValue>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
||||
Reference in New Issue
Block a user