use serde_json::Value;
use tokio::sync::mpsc;
use crate::channels::{MessagingSubscription, MessagingSubscriptionError, MessagingTask};
use crate::messages::ListenerType;
use crate::types::NormalizedMessage;
pub(super) struct SlackFilter {
pub(super) subscribed_channels: Option<Vec<String>>,
pub(super) allowed_senders: Vec<String>,
}
impl SlackFilter {
pub(super) fn new(subscribed_channels: Option<Vec<String>>) -> Self {
Self {
subscribed_channels,
allowed_senders: Vec::new(),
}
}
fn with_senders(mut self, allowed_senders: Vec<String>) -> Self {
self.allowed_senders = allowed_senders;
self
}
fn accepts(&self, channel: &str) -> bool {
self.subscribed_channels
.as_ref()
.is_none_or(|channels| channels.iter().any(|selected| selected == channel))
}
fn accepts_message(&self, message: &NormalizedMessage) -> bool {
let Some(channel) = message.metadata.get("channel_id").and_then(Value::as_str) else {
return false;
};
let sender = message.metadata.get("user_id").and_then(Value::as_str);
self.accepts(channel)
&& (self.allowed_senders.is_empty()
|| sender.is_some_and(|sender| self.allowed_senders.iter().any(|allowed| allowed == sender)))
}
}
pub(super) fn subscribe(
subscription: MessagingSubscription,
mut rx: mpsc::Receiver<NormalizedMessage>,
tx: mpsc::Sender<NormalizedMessage>,
) -> Result<MessagingTask, MessagingSubscriptionError> {
subscription.validate(ListenerType::Slack)?;
let policy = SlackFilter::new(subscription.subscribed_channels).with_senders(subscription.allowed_senders);
Ok(tokio::spawn(async move {
while let Some(message) = tokio::select! { _ = tx.closed() => None, message = rx.recv() => message } {
if policy.accepts_message(&message) && tx.send(message).await.is_err() {
break;
}
}
Ok(())
}))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn channel_policy_is_bound_to_each_subscription() {
let restricted = SlackFilter::new(Some(vec!["C123".to_owned()]));
assert!(restricted.accepts("C123"));
assert!(!restricted.accepts("C999"));
let unrestricted = SlackFilter::new(None);
assert!(unrestricted.accepts("C123"));
assert!(unrestricted.accepts("C999"));
assert!(
MessagingSubscription {
subscribed_channels: Some(Vec::new()),
allowed_senders: Vec::new()
}
.validate(ListenerType::Slack)
.is_err()
);
}
}