mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-05-24 17:20:49 +00:00
Update youmubot-core
This commit is contained in:
parent
3f115eaab0
commit
08d639944e
10 changed files with 167 additions and 354 deletions
|
@ -3,6 +3,7 @@ use rand::{
|
|||
thread_rng,
|
||||
};
|
||||
use serenity::{
|
||||
builder::CreateMessage,
|
||||
framework::standard::{
|
||||
macros::{command, group},
|
||||
Args, CommandError as Error, CommandResult,
|
||||
|
@ -62,13 +63,11 @@ pub async fn choose(ctx: &Context, m: &Message, mut args: Args) -> CommandResult
|
|||
let online_only = !flags.contains("everyone");
|
||||
|
||||
let users: Result<Vec<_>, Error> = {
|
||||
let guild = m.guild(ctx).unwrap();
|
||||
let presences = &guild.presences;
|
||||
let presences = m.guild(&ctx.cache).unwrap().presences.clone();
|
||||
let channel = m.channel_id.to_channel(&ctx).await?;
|
||||
if let Channel::Guild(channel) = channel {
|
||||
Ok(channel
|
||||
.members(&ctx)
|
||||
.await?
|
||||
.members(&ctx)?
|
||||
.into_iter()
|
||||
.filter(|v| !v.user.bot) // Filter out bots
|
||||
.filter(|v| {
|
||||
|
@ -84,9 +83,7 @@ pub async fn choose(ctx: &Context, m: &Message, mut args: Args) -> CommandResult
|
|||
})
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.map(future::ready)
|
||||
.collect::<stream::FuturesUnordered<_>>()
|
||||
.filter_map(|member| async move {
|
||||
.filter_map(|member| {
|
||||
// Filter by role if provided
|
||||
match role {
|
||||
Some(role) if member.roles.iter().any(|r| role == *r) => Some(member),
|
||||
|
@ -94,8 +91,7 @@ pub async fn choose(ctx: &Context, m: &Message, mut args: Args) -> CommandResult
|
|||
_ => None,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
.await)
|
||||
.collect())
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
|
@ -118,25 +114,27 @@ pub async fn choose(ctx: &Context, m: &Message, mut args: Args) -> CommandResult
|
|||
};
|
||||
|
||||
m.channel_id
|
||||
.send_message(&ctx, |c| {
|
||||
c.content(
|
||||
MessageBuilder::new()
|
||||
.push("👑 The Gensokyo gods have gathered around and decided, out of ")
|
||||
.push_bold(format!("{}", users.len()))
|
||||
.push(" ")
|
||||
.push(
|
||||
role.map(|r| format!("{}s", r.mention()))
|
||||
.unwrap_or_else(|| "potential prayers".to_owned()),
|
||||
)
|
||||
.push(", ")
|
||||
.push(winner.mention())
|
||||
.push(" will be ")
|
||||
.push_bold_safe(title)
|
||||
.push(". Congrats! 🎉 🎊 🥳")
|
||||
.build(),
|
||||
)
|
||||
.reference_message(m)
|
||||
})
|
||||
.send_message(
|
||||
&ctx,
|
||||
CreateMessage::new()
|
||||
.content(
|
||||
MessageBuilder::new()
|
||||
.push("👑 The Gensokyo gods have gathered around and decided, out of ")
|
||||
.push_bold(format!("{}", users.len()))
|
||||
.push(" ")
|
||||
.push(
|
||||
role.map(|r| format!("{}s", r.mention()))
|
||||
.unwrap_or_else(|| "potential prayers".to_owned()),
|
||||
)
|
||||
.push(", ")
|
||||
.push(winner.mention().to_string())
|
||||
.push(" will be ")
|
||||
.push_bold_safe(title)
|
||||
.push(". Congrats! 🎉 🎊 🥳")
|
||||
.build(),
|
||||
)
|
||||
.reference_message(m),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::db::Roles as DB;
|
||||
use serenity::{
|
||||
builder::EditMessage,
|
||||
framework::standard::{macros::command, Args, CommandResult},
|
||||
model::{
|
||||
channel::{Message, ReactionType},
|
||||
|
@ -100,7 +101,8 @@ async fn list(ctx: &Context, m: &Message, _: Args) -> CommandResult {
|
|||
m.push_line("```");
|
||||
m.push(format!("Page **{}/{}**", page + 1, pages));
|
||||
|
||||
msg.edit(ctx, |f| f.content(m.to_string())).await?;
|
||||
msg.edit(ctx, EditMessage::new().content(m.to_string()))
|
||||
.await?;
|
||||
Ok(true)
|
||||
})
|
||||
},
|
||||
|
@ -140,7 +142,7 @@ async fn toggle(ctx: &Context, m: &Message, mut args: Args) -> CommandResult {
|
|||
m.reply(&ctx, "This role is not self-assignable. Check the `listroles` command to see which role can be assigned.").await?;
|
||||
}
|
||||
Some(role) => {
|
||||
let mut member = guild.member(&ctx, m.author.id).await.unwrap();
|
||||
let member = guild.member(&ctx, m.author.id).await.unwrap();
|
||||
if member.roles.contains(&role.id) {
|
||||
member.remove_role(&ctx, &role).await?;
|
||||
m.reply(&ctx, format!("Role `{}` has been removed.", role.name))
|
||||
|
@ -252,7 +254,7 @@ async fn remove(ctx: &Context, m: &Message, mut args: Args) -> CommandResult {
|
|||
/// Parse a string as a role.
|
||||
fn role_from_string(role: &str, roles: &std::collections::HashMap<RoleId, Role>) -> Option<Role> {
|
||||
match role.parse::<u64>() {
|
||||
Ok(id) if roles.contains_key(&RoleId(id)) => roles.get(&RoleId(id)).cloned(),
|
||||
Ok(id) if roles.contains_key(&RoleId::new(id)) => roles.get(&RoleId::new(id)).cloned(),
|
||||
_ => roles
|
||||
.iter()
|
||||
.find_map(|(_, r)| if r.name == role { Some(r) } else { None })
|
||||
|
@ -417,7 +419,8 @@ mod reaction_watcher {
|
|||
use dashmap::DashMap;
|
||||
use flume::{Receiver, Sender};
|
||||
use serenity::{
|
||||
collector::ReactionAction,
|
||||
all::Reaction,
|
||||
builder::{CreateMessage, EditMessage},
|
||||
model::{
|
||||
channel::{Message, ReactionType},
|
||||
guild::Role as DiscordRole,
|
||||
|
@ -468,7 +471,10 @@ mod reaction_watcher {
|
|||
roles: Vec<(Role, DiscordRole, ReactionType)>,
|
||||
) -> Result<()> {
|
||||
let mut msg = channel
|
||||
.send_message(&ctx, |c| c.content("Youmu is setting up the message..."))
|
||||
.send_message(
|
||||
&ctx,
|
||||
CreateMessage::new().content("Youmu is setting up the message..."),
|
||||
)
|
||||
.await?;
|
||||
self.setup(&mut msg, ctx, guild, title, roles).await
|
||||
}
|
||||
|
@ -481,8 +487,9 @@ mod reaction_watcher {
|
|||
roles: Vec<(Role, DiscordRole, ReactionType)>,
|
||||
) -> Result<()> {
|
||||
// Send a message
|
||||
msg.edit(&ctx, |m| {
|
||||
m.content({
|
||||
msg.edit(
|
||||
&ctx,
|
||||
EditMessage::new().content({
|
||||
let mut builder = serenity::utils::MessageBuilder::new();
|
||||
builder
|
||||
.push_bold("Role Menu:")
|
||||
|
@ -492,16 +499,16 @@ mod reaction_watcher {
|
|||
.push_line("");
|
||||
for (role, discord_role, emoji) in &roles {
|
||||
builder
|
||||
.push(emoji)
|
||||
.push(emoji.to_string())
|
||||
.push(" ")
|
||||
.push_bold_safe(&discord_role.name)
|
||||
.push(": ")
|
||||
.push_line_safe(&role.description)
|
||||
.push_line("");
|
||||
}
|
||||
builder
|
||||
})
|
||||
})
|
||||
builder.build()
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
// Do reactions
|
||||
for (_, _, emoji) in &roles {
|
||||
|
@ -566,13 +573,19 @@ mod reaction_watcher {
|
|||
|
||||
async fn handle(ctx: Context, recv: Receiver<()>, guild: GuildId, message: MessageId) {
|
||||
let mut recv = recv.into_recv_async();
|
||||
let collect = || {
|
||||
serenity::collector::CollectReaction::new(&ctx)
|
||||
.message_id(message)
|
||||
.removed(true)
|
||||
};
|
||||
let mut collect = serenity::collector::collect(&ctx.shard, move |event| {
|
||||
match event {
|
||||
serenity::all::Event::ReactionAdd(r) => Some((r.reaction.clone(), true)),
|
||||
serenity::all::Event::ReactionRemove(r) => Some((r.reaction.clone(), false)),
|
||||
_ => None,
|
||||
}
|
||||
.filter(|(r, _)| r.message_id == message)
|
||||
});
|
||||
// serenity::collector::CollectReaction::new(&ctx)
|
||||
// .message_id(message)
|
||||
// .removed(true)
|
||||
loop {
|
||||
let reaction = match future::select(recv, collect()).await {
|
||||
let (reaction, is_add) = match future::select(recv, collect.next()).await {
|
||||
future::Either::Left(_) => break,
|
||||
future::Either::Right((r, new_recv)) => {
|
||||
recv = new_recv;
|
||||
|
@ -582,8 +595,9 @@ mod reaction_watcher {
|
|||
}
|
||||
}
|
||||
};
|
||||
eprintln!("{:?}", reaction);
|
||||
if let Err(e) = Self::handle_reaction(&ctx, guild, message, &reaction).await {
|
||||
eprintln!("{:?} {}", reaction, is_add);
|
||||
if let Err(e) = Self::handle_reaction(&ctx, guild, message, &reaction, is_add).await
|
||||
{
|
||||
eprintln!("Handling {:?}: {}", reaction, e);
|
||||
break;
|
||||
}
|
||||
|
@ -594,15 +608,16 @@ mod reaction_watcher {
|
|||
ctx: &Context,
|
||||
guild: GuildId,
|
||||
message: MessageId,
|
||||
reaction: &ReactionAction,
|
||||
reaction: &Reaction,
|
||||
is_add: bool,
|
||||
) -> Result<()> {
|
||||
let data = ctx.data.read().await;
|
||||
// Collect user
|
||||
let user_id = match reaction.as_inner_ref().user_id {
|
||||
let user_id = match reaction.user_id {
|
||||
Some(id) => id,
|
||||
None => return Ok(()),
|
||||
};
|
||||
let mut member = match guild.member(ctx, user_id).await.ok() {
|
||||
let member = match guild.member(ctx, user_id).await.ok() {
|
||||
Some(m) => m,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
@ -620,7 +635,7 @@ mod reaction_watcher {
|
|||
.ok_or_else(|| Error::msg("message is no longer a role list handler"))?
|
||||
.iter()
|
||||
.find_map(|(role, role_reaction)| {
|
||||
if &reaction.as_inner_ref().emoji == role_reaction {
|
||||
if &reaction.emoji == role_reaction {
|
||||
Some(role.id)
|
||||
} else {
|
||||
None
|
||||
|
@ -631,9 +646,10 @@ mod reaction_watcher {
|
|||
None => return Ok(()),
|
||||
};
|
||||
|
||||
match reaction {
|
||||
ReactionAction::Added(_) => member.add_role(&ctx, role).await.pls_ok(),
|
||||
ReactionAction::Removed(_) => member.remove_role(&ctx, role).await.pls_ok(),
|
||||
if is_add {
|
||||
member.add_role(&ctx, role).await.pls_ok();
|
||||
} else {
|
||||
member.remove_role(&ctx, role).await.pls_ok();
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,18 +1,10 @@
|
|||
use serenity::framework::standard::CommandError as Error;
|
||||
use serenity::{
|
||||
collector::ReactionAction,
|
||||
framework::standard::{macros::command, Args, CommandResult},
|
||||
model::{
|
||||
channel::{Message, ReactionType},
|
||||
id::UserId,
|
||||
},
|
||||
utils::MessageBuilder,
|
||||
};
|
||||
use serenity::all::{Message, ReactionType, UserId};
|
||||
use serenity::builder::{CreateEmbed, CreateEmbedAuthor, CreateMessage};
|
||||
use serenity::framework::standard::macros::command;
|
||||
use serenity::framework::standard::{Args, CommandError as Error, CommandResult};
|
||||
use serenity::{self, collector, utils::MessageBuilder};
|
||||
use std::collections::{HashMap as Map, HashSet as Set};
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
collections::{HashMap as Map, HashSet as Set},
|
||||
convert::TryFrom,
|
||||
};
|
||||
use youmubot_prelude::{Duration as ParseDuration, *};
|
||||
|
||||
#[command]
|
||||
|
@ -86,18 +78,18 @@ pub async fn vote(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult
|
|||
let author = msg.author.clone();
|
||||
let asked = msg.timestamp;
|
||||
let until = *asked + (chrono::Duration::from_std(*duration).unwrap());
|
||||
let panel = channel.send_message(&ctx, |c| {
|
||||
c.content("@here").embed(|e| {
|
||||
e.author(|au| {
|
||||
au.icon_url(author.avatar_url().unwrap_or_else(|| "".to_owned()))
|
||||
.name(&author.name)
|
||||
let panel = channel.send_message(&ctx,
|
||||
CreateMessage::new().content("@here").embed(
|
||||
CreateEmbed::new().author( {
|
||||
CreateEmbedAuthor::new(&author.name).icon_url(author.avatar_url().unwrap_or_else(|| "".to_owned()))
|
||||
})
|
||||
.title(format!("Please vote! Poll ends {}", until.format("<t:%s:R>")))
|
||||
.thumbnail("https://images-ext-2.discordapp.net/external/BK7injOyt4XT8yNfbCDV4mAkwoRy49YPfq-3IwCc_9M/http/cdn.i.ntere.st/p/9197498/image")
|
||||
.description(MessageBuilder::new().push_bold_line_safe(&question).push("\nThis question was asked by ").push(author.mention()))
|
||||
.description(
|
||||
MessageBuilder::new().push_bold_line_safe(&question).push("\nThis question was asked by ").push(author.mention().to_string()).build())
|
||||
.fields(fields.into_iter())
|
||||
})
|
||||
}).await?;
|
||||
)
|
||||
).await?;
|
||||
msg.delete(&ctx).await?;
|
||||
|
||||
// React on all the choices
|
||||
|
@ -115,37 +107,38 @@ pub async fn vote(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult
|
|||
.collect();
|
||||
|
||||
// Collect reactions...
|
||||
let user_reactions = panel
|
||||
.await_reactions(ctx)
|
||||
.removed(true)
|
||||
.timeout(*duration)
|
||||
.build()
|
||||
.fold(user_reactions, |mut set, reaction| async move {
|
||||
let (reaction, is_add) = match &*reaction {
|
||||
ReactionAction::Added(r) => (r, true),
|
||||
ReactionAction::Removed(r) => (r, false),
|
||||
};
|
||||
let users = if let ReactionType::Unicode(ref s) = reaction.emoji {
|
||||
if let Some(users) = set.get_mut(s.as_str()) {
|
||||
users
|
||||
} else {
|
||||
return set;
|
||||
}
|
||||
let message_id = panel.id;
|
||||
let user_reactions = collector::collect(&ctx.shard, move |event| {
|
||||
match event {
|
||||
serenity::all::Event::ReactionAdd(r) => Some((r.reaction.clone(), true)),
|
||||
serenity::all::Event::ReactionRemove(r) => Some((r.reaction.clone(), false)),
|
||||
_ => None,
|
||||
}
|
||||
.filter(|(r, _)| r.message_id == message_id)
|
||||
})
|
||||
.take_until(tokio::time::timeout(*duration, future::ready(())))
|
||||
.fold(user_reactions, |mut set, (reaction, is_add)| async move {
|
||||
let users = if let ReactionType::Unicode(ref s) = reaction.emoji {
|
||||
if let Some(users) = set.get_mut(s.as_str()) {
|
||||
users
|
||||
} else {
|
||||
return set;
|
||||
};
|
||||
let user_id = match reaction.user_id {
|
||||
Some(v) => v,
|
||||
None => return set,
|
||||
};
|
||||
if is_add {
|
||||
users.insert(user_id);
|
||||
} else {
|
||||
users.remove(&user_id);
|
||||
}
|
||||
set
|
||||
})
|
||||
.await;
|
||||
} else {
|
||||
return set;
|
||||
};
|
||||
let user_id = match reaction.user_id {
|
||||
Some(v) => v,
|
||||
None => return set,
|
||||
};
|
||||
if is_add {
|
||||
users.insert(user_id);
|
||||
} else {
|
||||
users.remove(&user_id);
|
||||
}
|
||||
set
|
||||
})
|
||||
.await;
|
||||
|
||||
// Handle choices
|
||||
let choice_map = choices.into_iter().collect::<Map<_, _>>();
|
||||
|
@ -171,13 +164,14 @@ pub async fn vote(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult
|
|||
}
|
||||
|
||||
channel
|
||||
.send_message(&ctx, |c| {
|
||||
c.content({
|
||||
.send_message(
|
||||
&ctx,
|
||||
CreateMessage::new().content({
|
||||
let mut content = MessageBuilder::new();
|
||||
content
|
||||
.push("@here, ")
|
||||
.push(asked.format("<t:%s:R>, "))
|
||||
.push(author.mention())
|
||||
.push(asked.format("<t:%s:R>, ").to_string())
|
||||
.push(author.mention().to_string())
|
||||
.push(" asked ")
|
||||
.push_bold_safe(&question)
|
||||
.push(", and here are the results!");
|
||||
|
@ -199,8 +193,8 @@ pub async fn vote(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult
|
|||
);
|
||||
});
|
||||
content.build()
|
||||
})
|
||||
})
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
panel.delete(&ctx).await?;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue