Core: asyncify Roles

This commit is contained in:
Natsu Kagami 2020-09-03 20:32:48 -04:00
parent 256ed3fe7c
commit 890cb21770
Signed by: nki
GPG key ID: 73376E117CD20735

View file

@ -1,6 +1,6 @@
use crate::db::Roles as DB; use crate::db::Roles as DB;
use serenity::{ use serenity::{
framework::standard::{macros::command, Args, CommandError as Error, CommandResult}, framework::standard::{macros::command, Args, CommandResult},
model::{channel::Message, guild::Role, id::RoleId}, model::{channel::Message, guild::Role, id::RoleId},
utils::MessageBuilder, utils::MessageBuilder,
}; };
@ -10,18 +10,22 @@ use youmubot_prelude::*;
#[description = "List all available roles in the server."] #[description = "List all available roles in the server."]
#[num_args(0)] #[num_args(0)]
#[only_in(guilds)] #[only_in(guilds)]
fn list(ctx: &mut Context, m: &Message, _: Args) -> CommandResult { async fn list(ctx: &Context, m: &Message, _: Args) -> CommandResult {
let guild_id = m.guild_id.unwrap(); // only_in(guilds) let guild_id = m.guild_id.unwrap(); // only_in(guilds)
let data = ctx.data.read().await;
let db = DB::open(&*ctx.data.read()); let db = DB::open(&*data);
let db = db.borrow()?; let roles = db
let roles = db.get(&guild_id).filter(|v| !v.is_empty()).cloned(); .borrow()?
.get(&guild_id)
.filter(|v| !v.is_empty())
.cloned();
match roles { match roles {
None => { None => {
m.reply(&ctx, "No roles available for assigning.")?; m.reply(&ctx, "No roles available for assigning.").await?;
} }
Some(v) => { Some(v) => {
let roles = guild_id.to_partial_guild(&ctx)?.roles; let roles = guild_id.to_partial_guild(&ctx).await?.roles;
let roles: Vec<_> = v let roles: Vec<_> = v
.into_iter() .into_iter()
.filter_map(|(_, role)| roles.get(&role.id).cloned().map(|r| (r, role.description))) .filter_map(|(_, role)| roles.get(&role.id).cloned().map(|r| (r, role.description)))
@ -29,16 +33,13 @@ fn list(ctx: &mut Context, m: &Message, _: Args) -> CommandResult {
const ROLES_PER_PAGE: usize = 8; const ROLES_PER_PAGE: usize = 8;
let pages = (roles.len() + ROLES_PER_PAGE - 1) / ROLES_PER_PAGE; let pages = (roles.len() + ROLES_PER_PAGE - 1) / ROLES_PER_PAGE;
let watcher = ctx.data.get_cloned::<ReactionWatcher>(); paginate(
watcher.paginate_fn( |page, ctx, msg| async move {
ctx.clone(),
m.channel_id,
move |page, e| {
let page = page as usize; let page = page as usize;
let start = page * ROLES_PER_PAGE; let start = page * ROLES_PER_PAGE;
let end = roles.len().min(start + ROLES_PER_PAGE); let end = roles.len().min(start + ROLES_PER_PAGE);
if end <= start { if end <= start {
return (e, Err(Error::from("No more roles to display"))); return Ok(false);
} }
let roles = &roles[start..end]; let roles = &roles[start..end];
let nw = roles // name width let nw = roles // name width
@ -91,46 +92,54 @@ fn list(ctx: &mut Context, m: &Message, _: Args) -> CommandResult {
m.push_line("```"); m.push_line("```");
m.push(format!("Page **{}/{}**", page + 1, pages)); m.push(format!("Page **{}/{}**", page + 1, pages));
(e.content(m.build()), Ok(())) msg.edit(ctx, |f| f.content(m.to_string())).await?;
Ok(true)
}, },
ctx,
m.channel_id,
std::time::Duration::from_secs(60 * 10), std::time::Duration::from_secs(60 * 10),
)?; )
.await?;
} }
}; };
Ok(()) Ok(())
} }
// async fn list_pager(
#[command("role")] #[command("role")]
#[description = "Toggle a role by its name or ID."] #[description = "Toggle a role by its name or ID."]
#[example = "\"IELTS / TOEFL\""] #[example = "\"IELTS / TOEFL\""]
#[num_args(1)] #[num_args(1)]
#[only_in(guilds)] #[only_in(guilds)]
fn toggle(ctx: &mut Context, m: &Message, mut args: Args) -> CommandResult { async fn toggle(ctx: &Context, m: &Message, mut args: Args) -> CommandResult {
let role = args.single_quoted::<String>()?; let role = args.single_quoted::<String>()?;
let guild_id = m.guild_id.unwrap(); let guild_id = m.guild_id.unwrap();
let roles = guild_id.to_partial_guild(&ctx)?.roles; let roles = guild_id.to_partial_guild(&ctx).await?.roles;
let role = role_from_string(&role, &roles); let role = role_from_string(&role, &roles);
match role { match role {
None => { None => {
m.reply(&ctx, "No such role exists")?; m.reply(&ctx, "No such role exists").await?;
} }
Some(role) Some(role)
if !DB::open(&*ctx.data.read()) if !DB::open(&*ctx.data.read().await)
.borrow()? .borrow()?
.get(&guild_id) .get(&guild_id)
.map(|g| g.contains_key(&role.id)) .map(|g| g.contains_key(&role.id))
.unwrap_or(false) => .unwrap_or(false) =>
{ {
m.reply(&ctx, "This role is not self-assignable. Check the `listroles` command to see which role can be assigned.")?; m.reply(&ctx, "This role is not self-assignable. Check the `listroles` command to see which role can be assigned.").await?;
} }
Some(role) => { Some(role) => {
let mut member = m.member(&ctx).ok_or(Error::from("Cannot find member"))?; let mut member = m.member(&ctx).await.unwrap();
if member.roles.contains(&role.id) { if member.roles.contains(&role.id) {
member.remove_role(&ctx, &role)?; member.remove_role(&ctx, &role).await?;
m.reply(&ctx, format!("Role `{}` has been removed.", role.name))?; m.reply(&ctx, format!("Role `{}` has been removed.", role.name))
.await?;
} else { } else {
member.add_role(&ctx, &role)?; member.add_role(&ctx, &role).await?;
m.reply(&ctx, format!("Role `{}` has been assigned.", role.name))?; m.reply(&ctx, format!("Role `{}` has been assigned.", role.name))
.await?;
} }
} }
}; };
@ -144,27 +153,28 @@ fn toggle(ctx: &mut Context, m: &Message, mut args: Args) -> CommandResult {
#[num_args(2)] #[num_args(2)]
#[required_permissions(MANAGE_ROLES)] #[required_permissions(MANAGE_ROLES)]
#[only_in(guilds)] #[only_in(guilds)]
fn add(ctx: &mut Context, m: &Message, mut args: Args) -> CommandResult { async fn add(ctx: &Context, m: &Message, mut args: Args) -> CommandResult {
let role = args.single_quoted::<String>()?; let role = args.single_quoted::<String>()?;
let description = args.single::<String>()?; let description = args.single::<String>()?;
let guild_id = m.guild_id.unwrap(); let guild_id = m.guild_id.unwrap();
let roles = guild_id.to_partial_guild(&ctx)?.roles; let roles = guild_id.to_partial_guild(&ctx).await?.roles;
let role = role_from_string(&role, &roles); let role = role_from_string(&role, &roles);
match role { match role {
None => { None => {
m.reply(&ctx, "No such role exists")?; m.reply(&ctx, "No such role exists").await?;
} }
Some(role) Some(role)
if DB::open(&*ctx.data.read()) if DB::open(&*ctx.data.read().await)
.borrow()? .borrow()?
.get(&guild_id) .get(&guild_id)
.map(|g| g.contains_key(&role.id)) .map(|g| g.contains_key(&role.id))
.unwrap_or(false) => .unwrap_or(false) =>
{ {
m.reply(&ctx, "This role already exists in the database.")?; m.reply(&ctx, "This role already exists in the database.")
.await?;
} }
Some(role) => { Some(role) => {
DB::open(&*ctx.data.read()) DB::open(&*ctx.data.read().await)
.borrow_mut()? .borrow_mut()?
.entry(guild_id) .entry(guild_id)
.or_default() .or_default()
@ -175,7 +185,7 @@ fn add(ctx: &mut Context, m: &Message, mut args: Args) -> CommandResult {
description, description,
}, },
); );
m.react(&ctx, "👌🏼")?; m.react(&ctx, '👌').await?;
} }
}; };
Ok(()) Ok(())
@ -188,31 +198,32 @@ fn add(ctx: &mut Context, m: &Message, mut args: Args) -> CommandResult {
#[num_args(1)] #[num_args(1)]
#[required_permissions(MANAGE_ROLES)] #[required_permissions(MANAGE_ROLES)]
#[only_in(guilds)] #[only_in(guilds)]
fn remove(ctx: &mut Context, m: &Message, mut args: Args) -> CommandResult { async fn remove(ctx: &Context, m: &Message, mut args: Args) -> CommandResult {
let role = args.single_quoted::<String>()?; let role = args.single_quoted::<String>()?;
let guild_id = m.guild_id.unwrap(); let guild_id = m.guild_id.unwrap();
let roles = guild_id.to_partial_guild(&ctx)?.roles; let roles = guild_id.to_partial_guild(&ctx).await?.roles;
let role = role_from_string(&role, &roles); let role = role_from_string(&role, &roles);
match role { match role {
None => { None => {
m.reply(&ctx, "No such role exists")?; m.reply(&ctx, "No such role exists").await?;
} }
Some(role) Some(role)
if !DB::open(&*ctx.data.read()) if !DB::open(&*ctx.data.read().await)
.borrow()? .borrow()?
.get(&guild_id) .get(&guild_id)
.map(|g| g.contains_key(&role.id)) .map(|g| g.contains_key(&role.id))
.unwrap_or(false) => .unwrap_or(false) =>
{ {
m.reply(&ctx, "This role does not exist in the assignable list.")?; m.reply(&ctx, "This role does not exist in the assignable list.")
.await?;
} }
Some(role) => { Some(role) => {
DB::open(&*ctx.data.read()) DB::open(&*ctx.data.read().await)
.borrow_mut()? .borrow_mut()?
.entry(guild_id) .entry(guild_id)
.or_default() .or_default()
.remove(&role.id); .remove(&role.id);
m.react(&ctx, "👌🏼")?; m.react(&ctx, '👌').await?;
} }
}; };
Ok(()) Ok(())