|
1 | 1 | use indoc::formatdoc; |
2 | 2 | use poise::{ |
3 | | - CreateReply, |
| 3 | + ChoiceParameter, CreateReply, |
4 | 4 | serenity_prelude::{ |
5 | 5 | ButtonStyle, Colour, ComponentInteractionDataKind, CreateActionRow, CreateButton, |
6 | 6 | CreateEmbed, CreateInteractionResponse, CreateInteractionResponseMessage, EditChannel, |
7 | | - GetMessages, GuildChannel, Mentionable, |
| 7 | + FormattedTimestamp, FormattedTimestampStyle, GetMessages, GuildChannel, Member, |
| 8 | + Mentionable, Timestamp, |
8 | 9 | futures::future::{Either, select}, |
9 | 10 | }, |
10 | 11 | }; |
11 | 12 | use std::{pin::pin, time::Duration}; |
12 | 13 | use tokio::time::Instant; |
13 | 14 |
|
14 | | -use crate::discord::{Context, Error}; |
| 15 | +use crate::discord::{Context, Error, utils::ROLE_MUTED}; |
15 | 16 |
|
16 | 17 | /// Manages slowmode for a channel. |
17 | 18 | #[poise::command( |
@@ -197,3 +198,111 @@ pub async fn nuke( |
197 | 198 | reply_handler.edit(ctx, reply).await?; |
198 | 199 | Ok(()) |
199 | 200 | } |
| 201 | + |
| 202 | +#[derive(Debug, ChoiceParameter)] |
| 203 | +enum MuteLength { |
| 204 | + #[name = "10 minutes"] |
| 205 | + Mins10, |
| 206 | + #[name = "20 minutes"] |
| 207 | + Mins20, |
| 208 | + #[name = "1 hour"] |
| 209 | + Hours1, |
| 210 | + #[name = "2 hours"] |
| 211 | + Hours2, |
| 212 | + #[name = "8 hours"] |
| 213 | + Hours8, |
| 214 | + #[name = "1 day"] |
| 215 | + Days1, |
| 216 | + #[name = "4 days"] |
| 217 | + Days4, |
| 218 | + #[name = "7 days"] |
| 219 | + Days7, |
| 220 | + #[name = "4 weeks"] |
| 221 | + Weeks4, |
| 222 | + // #[name = "1 month"] |
| 223 | + // Month1, |
| 224 | + // #[name = "1 year"] |
| 225 | + // Year1, |
| 226 | + #[name = "Indefinitely"] |
| 227 | + Indefinitely, |
| 228 | +} |
| 229 | + |
| 230 | +#[derive(Debug, ChoiceParameter)] |
| 231 | +enum YesNo { |
| 232 | + Yes, |
| 233 | + No, |
| 234 | +} |
| 235 | + |
| 236 | +// TODO: add view to confirm mute |
| 237 | +// TODO: use `reason` and `quiet` |
| 238 | +/// Staff command. Mutes a user. |
| 239 | +#[poise::command( |
| 240 | + slash_command, |
| 241 | + guild_only, |
| 242 | + default_member_permissions = "MANAGE_ROLES", |
| 243 | + required_bot_permissions = "MANAGE_ROLES" |
| 244 | +)] |
| 245 | +pub async fn mute( |
| 246 | + ctx: Context<'_>, |
| 247 | + #[description = "The user to mute."] mut member: Member, |
| 248 | + #[description = "The reason to mute the user."] _reason: Option<String>, |
| 249 | + #[description = "How long to mute the user for. Mutally exclusive to `until`."] |
| 250 | + mute_length: Option<MuteLength>, |
| 251 | + #[description = "Unix timestamp (in secs) for how long to keep user muted until. Mutally exclusive to `mute_length`."] |
| 252 | + until: Option<i64>, |
| 253 | + #[description = "Does not DM the user upon mute. Defaults to no."] _quiet: Option<YesNo>, |
| 254 | +) -> Result<(), Error> { |
| 255 | + let guild = ctx.guild_id().unwrap(); |
| 256 | + let now = Timestamp::now(); |
| 257 | + let end_time = |
| 258 | + match (mute_length, until) { |
| 259 | + (Some(_), Some(_)) => return Err( |
| 260 | + "Provided `mute_length` and `until` options when only one of them should be sent" |
| 261 | + .into(), |
| 262 | + ), |
| 263 | + (None, None) => return Err("One of `mute_length` and `until` should be sent".into()), |
| 264 | + (Some(duration_name), None) => { |
| 265 | + let duration = match duration_name { |
| 266 | + MuteLength::Mins10 => Some(Duration::from_mins(10).as_secs()), |
| 267 | + MuteLength::Mins20 => Some(Duration::from_mins(20).as_secs()), |
| 268 | + MuteLength::Hours1 => Some(Duration::from_hours(1).as_secs()), |
| 269 | + MuteLength::Hours2 => Some(Duration::from_hours(2).as_secs()), |
| 270 | + MuteLength::Hours8 => Some(Duration::from_hours(8).as_secs()), |
| 271 | + MuteLength::Days1 => Some(Duration::from_hours(24).as_secs()), |
| 272 | + MuteLength::Days4 => Some(Duration::from_hours(4 * 24).as_secs()), |
| 273 | + MuteLength::Days7 => Some(Duration::from_hours(7 * 24).as_secs()), |
| 274 | + MuteLength::Weeks4 => Some(Duration::from_hours(28 * 24).as_secs()), |
| 275 | + MuteLength::Indefinitely => None, |
| 276 | + }; |
| 277 | + if let Some(duration) = duration { |
| 278 | + Some(Timestamp::from_unix_timestamp( |
| 279 | + now.unix_timestamp() + duration as i64, |
| 280 | + )?) |
| 281 | + } else { |
| 282 | + None |
| 283 | + } |
| 284 | + } |
| 285 | + (None, Some(until)) => Some(Timestamp::from_unix_timestamp(until)?), |
| 286 | + }; |
| 287 | + if let Some(end_time) = end_time { |
| 288 | + member |
| 289 | + .disable_communication_until_datetime(ctx.http(), end_time) |
| 290 | + .await?; |
| 291 | + ctx.reply(format!( |
| 292 | + "{} was muted until {}.", |
| 293 | + member.mention(), |
| 294 | + FormattedTimestamp::new(end_time, Some(FormattedTimestampStyle::ShortDateTime)) |
| 295 | + )) |
| 296 | + .await?; |
| 297 | + } else { |
| 298 | + let roles = guild.roles(ctx.http()).await?; |
| 299 | + let mute_role = roles |
| 300 | + .values() |
| 301 | + .find(|role| role.name == ROLE_MUTED) |
| 302 | + .ok_or(format!("Could not find `{}` role", ROLE_MUTED))?; |
| 303 | + member.add_role(ctx.http(), mute_role.id).await?; |
| 304 | + ctx.reply(format!("{} was muted indefinitely.", member.mention())) |
| 305 | + .await?; |
| 306 | + } |
| 307 | + Ok(()) |
| 308 | +} |
0 commit comments