use uuid::Uuid;
use crate::application::service::chatter_acl::MessagingIdentity;
use crate::infrastructure::persistence::channel_member_repository::{
ChannelMemberRepository, MemberKey,
};
use crate::infrastructure::persistence::channel_repository::ChannelRepository;
#[derive(Debug, Clone, serde::Serialize)]
pub struct ChannelSearchHit {
pub channel_id: Uuid,
pub name: Option<String>,
pub channel_type: String,
pub is_member: bool,
}
#[derive(Debug, thiserror::Error)]
pub enum ChannelQueryError {
#[error("db: {0}")]
Db(#[from] sqlx::Error),
#[error("not a channel member")]
NotAMember,
}
pub struct ChannelQueryService {
pool: sqlx::PgPool,
pub search_limit: i64,
}
impl ChannelQueryService {
pub fn new(pool: sqlx::PgPool) -> Self {
Self { pool, search_limit: 20 }
}
pub async fn members(
&self,
identity: &MessagingIdentity,
channel_id: Uuid,
) -> Result<Vec<(Uuid, Option<Uuid>, Option<Uuid>)>, ChannelQueryError> {
self.require_member(channel_id, identity).await?;
let mut conn = self.pool.acquire().await?;
ChannelRepository::list_members(&mut conn, channel_id).await.map_err(Into::into)
}
pub async fn pinned_messages(
&self,
identity: &MessagingIdentity,
channel_id: Uuid,
) -> Result<Vec<Uuid>, ChannelQueryError> {
self.require_member(channel_id, identity).await?;
let mut conn = self.pool.acquire().await?;
ChannelRepository::pinned_message_ids(&mut conn, channel_id).await.map_err(Into::into)
}
pub async fn search(
&self,
identity: &MessagingIdentity,
term: Option<&str>,
) -> Result<Vec<ChannelSearchHit>, ChannelQueryError> {
let (partner_id, guest_id) = match identity {
MessagingIdentity::User { partner_id } => (Some(*partner_id), None),
MessagingIdentity::Guest { guest_id } => (None, Some(*guest_id)),
};
let rows =
ChannelRepository::search_channels(&self.pool, partner_id, guest_id, term.unwrap_or(""), self.search_limit)
.await?;
Ok(rows
.into_iter()
.map(|(channel_id, name, channel_type, is_member)| ChannelSearchHit {
channel_id,
name,
channel_type,
is_member,
})
.collect())
}
async fn require_member(
&self,
channel_id: Uuid,
identity: &MessagingIdentity,
) -> Result<(), ChannelQueryError> {
let mut conn = self.pool.acquire().await?;
let member = ChannelMemberRepository::member_id(
&mut conn,
&MemberKey { channel_id, identity },
false,
)
.await?;
match member {
Some(_) => Ok(()),
None => Err(ChannelQueryError::NotAMember),
}
}
}