1use std::{fmt::Debug, sync::Arc};
2
3use async_fn_traits::AsyncFn1;
4use async_trait::async_trait;
5use stoat_models::v0::Channel;
6use stoat_permissions::ChannelPermission;
7
8use crate::{Error, commands::Context};
9
10#[async_trait]
11pub trait Check<
12 E: From<Error> + Clone + Debug + Send + Sync + 'static,
13 S: Debug + Clone + Send + Sync + 'static,
14>: Send + Sync + 'static
15{
16 async fn run(&self, context: Context<E, S>) -> Result<bool, E>;
17}
18
19#[async_trait]
20impl<E, S, F> Check<E, S> for F
21where
22 E: From<Error> + Clone + Debug + Send + Sync + 'static,
23 S: Debug + Clone + Send + Sync + 'static,
24 F: AsyncFn1<Context<E, S>, Output = Result<bool, E>> + Send + Sync + 'static,
25 F::OutputFuture: Send + Sync,
26{
27 async fn run(&self, context: Context<E, S>) -> Result<bool, E> {
28 (self)(context).await
29 }
30}
31
32pub struct HasChannelPermissions(Vec<ChannelPermission>);
33
34impl HasChannelPermissions {
35 pub fn new(permissions: Vec<ChannelPermission>) -> Self {
36 Self(permissions)
37 }
38}
39
40#[async_trait]
41impl<
42 E: From<Error> + Clone + Debug + Send + Sync + 'static,
43 S: Debug + Clone + Send + Sync + 'static,
44> Check<E, S> for HasChannelPermissions
45{
46 async fn run(&self, context: Context<E, S>) -> Result<bool, E> {
47 let permissions = context.get_author_channel_permissions().await;
48
49 for perm in &self.0 {
50 if !permissions.has(*perm as u64) {
51 return Err(Error::MissingChannelPermission { permissions: *perm }.into());
52 };
53 }
54
55 Ok(true)
56 }
57}
58
59pub struct HasServerPermissions(Vec<ChannelPermission>);
60
61impl HasServerPermissions {
62 pub fn new(permissions: Vec<ChannelPermission>) -> Self {
63 Self(permissions)
64 }
65}
66
67#[async_trait]
68impl<
69 E: From<Error> + Clone + Debug + Send + Sync + 'static,
70 S: Debug + Clone + Send + Sync + 'static,
71> Check<E, S> for HasServerPermissions
72{
73 async fn run(&self, context: Context<E, S>) -> Result<bool, E> {
74 let permissions = context.get_author_server_permissions().await;
75
76 for perm in &self.0 {
77 if !permissions.has(*perm as u64) {
78 return Err(Error::MissingChannelPermission { permissions: *perm }.into());
79 };
80 }
81
82 Ok(true)
83 }
84}
85
86pub struct CheckAny<E, S>(pub Arc<Vec<Box<dyn Check<E, S>>>>);
87
88#[async_trait]
89impl<
90 E: From<Error> + Clone + Debug + Send + Sync + 'static,
91 S: Debug + Clone + Send + Sync + 'static,
92> Check<E, S> for CheckAny<E, S>
93{
94 async fn run(&self, context: Context<E, S>) -> Result<bool, E> {
95 for check in self.0.iter() {
96 if check.run(context.clone()).await.unwrap_or_default() == true {
97 return Ok(true);
98 }
99 }
100
101 Err(Error::CheckFailure.into())
102 }
103}
104
105impl<E, S> CheckAny<E, S> {
106 pub fn new(checks: Vec<Box<dyn Check<E, S>>>) -> Self {
107 Self(Arc::new(checks))
108 }
109}
110
111pub async fn server_only<
112 E: From<Error> + Clone + Debug + Send + Sync + 'static,
113 S: Debug + Clone + Send + Sync + 'static,
114>(
115 context: Context<E, S>,
116) -> Result<bool, E> {
117 match context.get_current_channel() {
118 Ok(Channel::TextChannel { .. }) => Ok(true),
119 _ => Err(Error::NotInServer.into()),
120 }
121}
122
123pub async fn dm_only<
124 E: From<Error> + Clone + Debug + Send + Sync + 'static,
125 S: Debug + Clone + Send + Sync + 'static,
126>(
127 context: Context<E, S>,
128) -> Result<bool, E> {
129 match context.get_current_channel() {
130 Ok(
131 Channel::DirectMessage { .. } | Channel::Group { .. } | Channel::SavedMessages { .. },
132 ) => Ok(true),
133 _ => Err(Error::NotInDM.into()),
134 }
135}
136
137pub async fn is_owner<
138 E: From<Error> + Clone + Debug + Send + Sync + 'static,
139 S: Debug + Clone + Send + Sync + 'static,
140>(
141 context: Context<E, S>,
142) -> Result<bool, E> {
143 if let Some(user) = context.cache.get_current_user() {
144 if let Some(bot) = user.bot {
145 if &bot.owner_id == &context.message.author {
146 return Ok(true);
147 };
148 };
149 };
150
151 Err(Error::NotOwner.into())
152}
153
154pub async fn is_nsfw<
155 E: From<Error> + Clone + Debug + Send + Sync + 'static,
156 S: Debug + Clone + Send + Sync + 'static,
157>(
158 context: Context<E, S>,
159) -> Result<bool, E> {
160 let channel = context.get_current_channel()?;
161
162 let is_nsfw = match channel {
163 Channel::DirectMessage { .. } | Channel::SavedMessages { .. } => true,
164 Channel::Group { nsfw, .. } | Channel::TextChannel { nsfw, .. } => nsfw,
165 };
166
167 if is_nsfw {
168 Ok(true)
169 } else {
170 Err(Error::NotNsfw.into())
171 }
172}