use std::{fmt::Debug, sync::Arc};
use async_fn_traits::AsyncFn1;
use async_trait::async_trait;
use stoat_models::v0::Channel;
use stoat_permissions::ChannelPermission;
use crate::{Error, commands::Context};
#[async_trait]
pub trait Check<
E: From<Error> + Clone + Debug + Send + Sync + 'static,
S: Debug + Clone + Send + Sync + 'static,
>: Send + Sync + 'static
{
async fn run(&self, context: Context<E, S>) -> Result<bool, E>;
}
#[async_trait]
impl<E, S, F> Check<E, S> for F
where
E: From<Error> + Clone + Debug + Send + Sync + 'static,
S: Debug + Clone + Send + Sync + 'static,
F: AsyncFn1<Context<E, S>, Output = Result<bool, E>> + Send + Sync + 'static,
F::OutputFuture: Send + Sync,
{
async fn run(&self, context: Context<E, S>) -> Result<bool, E> {
(self)(context).await
}
}
pub struct HasChannelPermissions(Vec<ChannelPermission>);
impl HasChannelPermissions {
pub fn new(permissions: Vec<ChannelPermission>) -> Self {
Self(permissions)
}
}
#[async_trait]
impl<
E: From<Error> + Clone + Debug + Send + Sync + 'static,
S: Debug + Clone + Send + Sync + 'static,
> Check<E, S> for HasChannelPermissions
{
async fn run(&self, context: Context<E, S>) -> Result<bool, E> {
let permissions = context.get_author_channel_permissions().await;
for perm in &self.0 {
if !permissions.has(*perm as u64) {
return Err(Error::MissingChannelPermission { permissions: *perm }.into());
};
}
Ok(true)
}
}
pub struct HasServerPermissions(Vec<ChannelPermission>);
impl HasServerPermissions {
pub fn new(permissions: Vec<ChannelPermission>) -> Self {
Self(permissions)
}
}
#[async_trait]
impl<
E: From<Error> + Clone + Debug + Send + Sync + 'static,
S: Debug + Clone + Send + Sync + 'static,
> Check<E, S> for HasServerPermissions
{
async fn run(&self, context: Context<E, S>) -> Result<bool, E> {
let permissions = context.get_author_server_permissions().await;
for perm in &self.0 {
if !permissions.has(*perm as u64) {
return Err(Error::MissingChannelPermission { permissions: *perm }.into());
};
}
Ok(true)
}
}
pub struct CheckAny<E, S>(pub Arc<Vec<Box<dyn Check<E, S>>>>);
#[async_trait]
impl<
E: From<Error> + Clone + Debug + Send + Sync + 'static,
S: Debug + Clone + Send + Sync + 'static,
> Check<E, S> for CheckAny<E, S>
{
async fn run(&self, context: Context<E, S>) -> Result<bool, E> {
for check in self.0.iter() {
if check.run(context.clone()).await.unwrap_or_default() == true {
return Ok(true);
}
}
Err(Error::CheckFailure.into())
}
}
impl<E, S> CheckAny<E, S> {
pub fn new(checks: Vec<Box<dyn Check<E, S>>>) -> Self {
Self(Arc::new(checks))
}
}
pub async fn server_only<
E: From<Error> + Clone + Debug + Send + Sync + 'static,
S: Debug + Clone + Send + Sync + 'static,
>(
context: Context<E, S>,
) -> Result<bool, E> {
match context.get_current_channel() {
Ok(Channel::TextChannel { .. }) => Ok(true),
_ => Err(Error::NotInServer.into()),
}
}
pub async fn dm_only<
E: From<Error> + Clone + Debug + Send + Sync + 'static,
S: Debug + Clone + Send + Sync + 'static,
>(
context: Context<E, S>,
) -> Result<bool, E> {
match context.get_current_channel() {
Ok(
Channel::DirectMessage { .. } | Channel::Group { .. } | Channel::SavedMessages { .. },
) => Ok(true),
_ => Err(Error::NotInDM.into()),
}
}
pub async fn is_owner<
E: From<Error> + Clone + Debug + Send + Sync + 'static,
S: Debug + Clone + Send + Sync + 'static,
>(
context: Context<E, S>,
) -> Result<bool, E> {
if let Some(user) = context.cache.get_current_user() {
if let Some(bot) = user.bot {
if &bot.owner_id == &context.message.author {
return Ok(true);
};
};
};
Err(Error::NotOwner.into())
}
pub async fn is_nsfw<
E: From<Error> + Clone + Debug + Send + Sync + 'static,
S: Debug + Clone + Send + Sync + 'static,
>(
context: Context<E, S>,
) -> Result<bool, E> {
let channel = context.get_current_channel()?;
let is_nsfw = match channel {
Channel::DirectMessage { .. } | Channel::SavedMessages { .. } => true,
Channel::Group { nsfw, .. } | Channel::TextChannel { nsfw, .. } => nsfw,
};
if is_nsfw {
Ok(true)
} else {
Err(Error::NotNsfw.into())
}
}