Core: asyncify choose and implement role filter

This commit is contained in:
Natsu Kagami 2020-09-06 22:51:20 -04:00
parent 9975aa5880
commit 5f08845d88
Signed by: nki
GPG key ID: 73376E117CD20735

View file

@ -9,6 +9,7 @@ use serenity::{
}, },
model::{ model::{
channel::{Channel, Message}, channel::{Channel, Message},
id::RoleId,
user::OnlineStatus, user::OnlineStatus,
}, },
utils::MessageBuilder, utils::MessageBuilder,
@ -30,39 +31,57 @@ struct Community;
#[command] #[command]
#[description = r"👑 Randomly choose an active member and mention them! #[description = r"👑 Randomly choose an active member and mention them!
Note that only online/idle users in the channel are chosen from."] Note that only online/idle users in the channel are chosen from."]
#[usage = "[title = the chosen one]"] #[usage = "[title = the chosen one] / [limited roles = everyone online]"]
#[example = "the strongest in Gensokyo"] #[example = "the strongest in Gensokyo"]
#[bucket = "community"] #[bucket = "community"]
#[max_args(1)] #[max_args(2)]
pub fn choose(ctx: &mut Context, m: &Message, mut args: Args) -> CommandResult { pub async fn choose(ctx: &Context, m: &Message, mut args: Args) -> CommandResult {
let title = if args.is_empty() { let title = if args.is_empty() {
"the chosen one".to_owned() "the chosen one".to_owned()
} else { } else {
args.single::<String>()? args.single::<String>()?
}; };
let role = match args.single::<RoleId>().ok() {
Some(v) => v.to_role_cached(&ctx).await,
None => None,
};
let users: Result<Vec<_>, Error> = { let users: Result<Vec<_>, Error> = {
let guild = m.guild(&ctx).unwrap(); let guild = m.guild(&ctx).await.unwrap();
let guild = guild.read();
let presences = &guild.presences; let presences = &guild.presences;
let channel = m.channel_id.to_channel(&ctx)?; let channel = m.channel_id.to_channel(&ctx).await?;
if let Channel::Guild(channel) = channel { if let Channel::Guild(channel) = channel {
let channel = channel.read();
Ok(channel Ok(channel
.members(&ctx)? .members(&ctx)
.await?
.into_iter() .into_iter()
.filter(|v| !v.user.read().bot) .filter(|v| !v.user.bot) // Filter out bots
.map(|v| v.user_id())
.filter(|v| { .filter(|v| {
// Filter out only online people
presences presences
.get(v) .get(&v.user.id)
.map(|presence| { .map(|presence| {
presence.status == OnlineStatus::Online presence.status == OnlineStatus::Online
|| presence.status == OnlineStatus::Idle || presence.status == OnlineStatus::Idle
}) })
.unwrap_or(false) .unwrap_or(false)
}) })
.collect()) .map(|mem| future::ready(mem))
.collect::<stream::FuturesUnordered<_>>()
.filter(|member| async {
// Filter by role if provided
if let Some(role) = role {
member
.roles(&ctx)
.await
.map(|roles| roles.into_iter().any(|r| role.id == r.id))
.unwrap_or(false)
} else {
true
}
})
.collect()
.await)
} else { } else {
panic!() panic!()
} }
@ -73,7 +92,8 @@ pub fn choose(ctx: &mut Context, m: &Message, mut args: Args) -> CommandResult {
m.reply( m.reply(
&ctx, &ctx,
"🍰 Have this cake for yourself because no-one is here for the gods to pick.", "🍰 Have this cake for yourself because no-one is here for the gods to pick.",
)?; )
.await?;
return Ok(()); return Ok(());
} }
@ -83,19 +103,26 @@ pub fn choose(ctx: &mut Context, m: &Message, mut args: Args) -> CommandResult {
&users[uniform.sample(&mut rng)] &users[uniform.sample(&mut rng)]
}; };
m.channel_id.send_message(&ctx, |c| { m.channel_id
.send_message(&ctx, |c| {
c.content( c.content(
MessageBuilder::new() MessageBuilder::new()
.push("👑 The Gensokyo gods have gathered around and decided, out of ") .push("👑 The Gensokyo gods have gathered around and decided, out of ")
.push_bold(format!("{}", users.len())) .push_bold(format!("{}", users.len()))
.push(" potential prayers, ") .push(" ")
.push(
role.map(|r| r.mention() + "s")
.unwrap_or("potential prayers".to_owned()),
)
.push(", ")
.push(winner.mention()) .push(winner.mention())
.push(" will be ") .push(" will be ")
.push_bold_safe(title) .push_bold_safe(title)
.push(". Congrats! 🎉 🎊 🥳") .push(". Congrats! 🎉 🎊 🥳")
.build(), .build(),
) )
})?; })
.await?;
Ok(()) Ok(())
} }