refactor!: use poise 0.6.1
This commit is contained in:
parent
203ba111cc
commit
7252ced3cb
16 changed files with 700 additions and 512 deletions
|
@ -1,11 +1,16 @@
|
|||
use crate::{consts, Context};
|
||||
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use poise::serenity_prelude::CreateEmbed;
|
||||
use poise::CreateReply;
|
||||
|
||||
/// Returns the number of members in the server
|
||||
#[poise::command(slash_command, prefix_command)]
|
||||
pub async fn members(ctx: Context<'_>) -> Result<()> {
|
||||
let guild = ctx.guild().ok_or_else(|| eyre!("Couldn't fetch guild!"))?;
|
||||
let guild = ctx
|
||||
.guild()
|
||||
.ok_or_else(|| eyre!("Couldn't fetch guild!"))?
|
||||
.to_owned();
|
||||
|
||||
let count = guild.member_count;
|
||||
let online = if let Some(count) = guild.approximate_presence_count {
|
||||
|
@ -14,13 +19,12 @@ pub async fn members(ctx: Context<'_>) -> Result<()> {
|
|||
"Undefined".to_string()
|
||||
};
|
||||
|
||||
ctx.send(|m| {
|
||||
m.embed(|e| {
|
||||
e.title(format!("{count} total members!"))
|
||||
.description(format!("{online} online members"))
|
||||
.color(consts::COLORS["blue"])
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
let embed = CreateEmbed::new()
|
||||
.title(format!("{count} total members!"))
|
||||
.description(format!("{online} online members"))
|
||||
.color(consts::COLORS["blue"]);
|
||||
let reply = CreateReply::default().embed(embed);
|
||||
|
||||
ctx.send(reply).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ use crate::api::rory::get_rory;
|
|||
use crate::Context;
|
||||
|
||||
use color_eyre::eyre::Result;
|
||||
use poise::serenity_prelude::{CreateEmbed, CreateEmbedFooter};
|
||||
use poise::CreateReply;
|
||||
|
||||
/// Gets a Rory photo!
|
||||
#[poise::command(slash_command, prefix_command)]
|
||||
|
@ -11,19 +13,22 @@ pub async fn rory(
|
|||
) -> Result<()> {
|
||||
let rory = get_rory(id).await?;
|
||||
|
||||
ctx.send(|m| {
|
||||
m.embed(|e| {
|
||||
if let Some(error) = rory.error {
|
||||
e.title("Error!").description(error)
|
||||
} else {
|
||||
e.title("Rory :3")
|
||||
.url(&rory.url)
|
||||
.image(rory.url)
|
||||
.footer(|f| f.text(format!("ID {}", rory.id)))
|
||||
}
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
let embed = {
|
||||
let embed = CreateEmbed::new();
|
||||
if let Some(error) = rory.error {
|
||||
embed.title("Error!").description(error)
|
||||
} else {
|
||||
let footer = CreateEmbedFooter::new(format!("ID {}", rory.id));
|
||||
embed
|
||||
.title("Rory :3")
|
||||
.url(&rory.url)
|
||||
.image(rory.url)
|
||||
.footer(footer)
|
||||
}
|
||||
};
|
||||
|
||||
let reply = CreateReply::default().embed(embed);
|
||||
ctx.send(reply).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::Context;
|
||||
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use poise::serenity_prelude::{CreateEmbed, CreateEmbedAuthor, CreateMessage};
|
||||
|
||||
/// Say something through the bot
|
||||
#[poise::command(
|
||||
|
@ -11,7 +12,10 @@ use color_eyre::eyre::{eyre, Result};
|
|||
required_permissions = "MODERATE_MEMBERS"
|
||||
)]
|
||||
pub async fn say(ctx: Context<'_>, #[description = "Just content?"] content: String) -> Result<()> {
|
||||
let guild = ctx.guild().ok_or_else(|| eyre!("Couldn't get guild!"))?;
|
||||
let guild = ctx
|
||||
.guild()
|
||||
.ok_or_else(|| eyre!("Couldn't get guild!"))?
|
||||
.to_owned();
|
||||
let channel = ctx
|
||||
.guild_channel()
|
||||
.await
|
||||
|
@ -28,23 +32,16 @@ pub async fn say(ctx: Context<'_>, #[description = "Just content?"] content: Str
|
|||
.find(|c| c.0 == &channel_id)
|
||||
.ok_or_else(|| eyre!("Couldn't get log channel from guild!"))?;
|
||||
|
||||
log_channel
|
||||
.1
|
||||
.clone()
|
||||
.guild()
|
||||
.ok_or_else(|| eyre!("Couldn't cast channel we found from guild as GuildChannel?????"))?
|
||||
.send_message(ctx, |m| {
|
||||
m.embed(|e| {
|
||||
e.title("Say command used!")
|
||||
.description(content)
|
||||
.author(|a| {
|
||||
a.name(ctx.author().tag()).icon_url(
|
||||
ctx.author().avatar_url().unwrap_or("undefined".to_string()),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
let author = CreateEmbedAuthor::new(ctx.author().tag())
|
||||
.icon_url(ctx.author().avatar_url().unwrap_or("Undefined".to_string()));
|
||||
|
||||
let embed = CreateEmbed::default()
|
||||
.title("Say command used!")
|
||||
.description(content)
|
||||
.author(author);
|
||||
|
||||
let message = CreateMessage::new().embed(embed);
|
||||
log_channel.1.send_message(ctx, message).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use crate::{consts::COLORS, Context};
|
||||
use crate::{consts, Context};
|
||||
|
||||
use color_eyre::eyre::{Context as _, Result};
|
||||
use poise::serenity_prelude::CreateEmbed;
|
||||
use poise::CreateReply;
|
||||
|
||||
/// Returns GitHub stargazer count
|
||||
#[poise::command(slash_command, prefix_command)]
|
||||
|
@ -19,13 +21,12 @@ pub async fn stars(ctx: Context<'_>) -> Result<()> {
|
|||
"undefined".to_string()
|
||||
};
|
||||
|
||||
ctx.send(|m| {
|
||||
m.embed(|e| {
|
||||
e.title(format!("⭐ {count} total stars!"))
|
||||
.color(COLORS["yellow"])
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
let embed = CreateEmbed::new()
|
||||
.title(format!("⭐ {count} total stars!"))
|
||||
.color(consts::COLORS["yellow"]);
|
||||
let reply = CreateReply::default().embed(embed);
|
||||
|
||||
ctx.send(reply).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@ use std::env;
|
|||
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use once_cell::sync::Lazy;
|
||||
use poise::serenity_prelude::{Color, User};
|
||||
use poise::serenity_prelude::{Color, CreateEmbed, User};
|
||||
use poise::CreateReply;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
|
||||
static TAGS: Lazy<Vec<Tag>> = Lazy::new(|| serde_json::from_str(env!("TAGS")).unwrap());
|
||||
|
@ -25,36 +26,40 @@ pub async fn tag(
|
|||
|
||||
let frontmatter = &tag.frontmatter;
|
||||
|
||||
ctx.send(|m| {
|
||||
if let Some(user) = user {
|
||||
m.content(format!("<@{}>", user.id));
|
||||
let embed = {
|
||||
let mut e = CreateEmbed::new();
|
||||
|
||||
if let Some(color) = &frontmatter.color {
|
||||
let color = *consts::COLORS
|
||||
.get(color.as_str())
|
||||
.unwrap_or(&Color::default());
|
||||
e = e.color(color);
|
||||
}
|
||||
|
||||
m.embed(|e| {
|
||||
e.title(&frontmatter.title);
|
||||
e.description(&tag.content);
|
||||
if let Some(image) = &frontmatter.image {
|
||||
e = e.image(image);
|
||||
}
|
||||
|
||||
if let Some(color) = &frontmatter.color {
|
||||
let color = *consts::COLORS
|
||||
.get(color.as_str())
|
||||
.unwrap_or(&Color::default());
|
||||
e.color(color);
|
||||
if let Some(fields) = &frontmatter.fields {
|
||||
for field in fields {
|
||||
e = e.field(&field.name, &field.value, field.inline);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(image) = &frontmatter.image {
|
||||
e.image(image);
|
||||
}
|
||||
e
|
||||
};
|
||||
|
||||
if let Some(fields) = &frontmatter.fields {
|
||||
for field in fields {
|
||||
e.field(&field.name, &field.value, field.inline);
|
||||
}
|
||||
}
|
||||
let reply = {
|
||||
let mut r = CreateReply::default();
|
||||
|
||||
e
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
if let Some(user) = user {
|
||||
r = r.content(format!("<@{}>", user.id));
|
||||
}
|
||||
|
||||
r.embed(embed)
|
||||
};
|
||||
|
||||
ctx.send(reply).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ use crate::Data;
|
|||
|
||||
use color_eyre::eyre::Report;
|
||||
use log::*;
|
||||
use poise::serenity_prelude::Timestamp;
|
||||
use poise::FrameworkError;
|
||||
use poise::serenity_prelude::{CreateEmbed, Timestamp};
|
||||
use poise::{CreateReply, FrameworkError};
|
||||
|
||||
pub async fn handle(error: FrameworkError<'_, Data, Report>) {
|
||||
match error {
|
||||
|
@ -12,23 +12,23 @@ pub async fn handle(error: FrameworkError<'_, Data, Report>) {
|
|||
error, framework, ..
|
||||
} => {
|
||||
error!("Error setting up client! Bailing out");
|
||||
framework.shard_manager().lock().await.shutdown_all().await;
|
||||
framework.shard_manager().shutdown_all().await;
|
||||
|
||||
panic!("{error}")
|
||||
}
|
||||
|
||||
FrameworkError::Command { error, ctx } => {
|
||||
FrameworkError::Command { error, ctx, .. } => {
|
||||
error!("Error in command {}:\n{error:?}", ctx.command().name);
|
||||
ctx.send(|c| {
|
||||
c.embed(|e| {
|
||||
e.title("Something went wrong!")
|
||||
.description("oopsie")
|
||||
.timestamp(Timestamp::now())
|
||||
.color(COLORS["red"])
|
||||
})
|
||||
})
|
||||
.await
|
||||
.ok();
|
||||
|
||||
let embed = CreateEmbed::new()
|
||||
.title("Something went wrong!")
|
||||
.description("oopsie")
|
||||
.timestamp(Timestamp::now())
|
||||
.color(COLORS["red"]);
|
||||
|
||||
let reply = CreateReply::default().embed(embed);
|
||||
|
||||
ctx.send(reply).await.ok();
|
||||
}
|
||||
|
||||
FrameworkError::EventHandler {
|
||||
|
@ -36,13 +36,17 @@ pub async fn handle(error: FrameworkError<'_, Data, Report>) {
|
|||
ctx: _,
|
||||
event,
|
||||
framework: _,
|
||||
..
|
||||
} => {
|
||||
error!("Error while handling event {}:\n{error:?}", event.name());
|
||||
error!(
|
||||
"Error while handling event {}:\n{error:?}",
|
||||
event.snake_case_name()
|
||||
);
|
||||
}
|
||||
|
||||
error => {
|
||||
if let Err(e) = poise::builtins::on_error(error).await {
|
||||
error!("Unhandled error occured:\n{e:#?}");
|
||||
error!("Unhandled error occurred:\n{e:#?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@ use crate::Data;
|
|||
|
||||
use color_eyre::eyre::Result;
|
||||
use log::*;
|
||||
use poise::serenity_prelude::{Context, Message};
|
||||
use poise::serenity_prelude::{
|
||||
Context, CreateAllowedMentions, CreateEmbed, CreateMessage, Message,
|
||||
};
|
||||
|
||||
mod issues;
|
||||
mod providers;
|
||||
|
@ -17,16 +19,16 @@ pub async fn handle(ctx: &Context, message: &Message, data: &Data) -> Result<()>
|
|||
let log = find_log(message).await;
|
||||
|
||||
if log.is_err() {
|
||||
channel
|
||||
.send_message(ctx, |m| {
|
||||
m.reference_message(message)
|
||||
.allowed_mentions(|am| am.replied_user(true))
|
||||
.embed(|e| {
|
||||
e.title("Analyze failed!")
|
||||
.description("Couldn't download log")
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
let embed = CreateEmbed::new()
|
||||
.title("Analyze failed!")
|
||||
.description("Couldn't download log");
|
||||
let allowed_mentions = CreateAllowedMentions::new().replied_user(true);
|
||||
let our_message = CreateMessage::new()
|
||||
.reference_message(message)
|
||||
.allowed_mentions(allowed_mentions)
|
||||
.embed(embed);
|
||||
|
||||
channel.send_message(ctx, our_message).await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -38,31 +40,32 @@ pub async fn handle(ctx: &Context, message: &Message, data: &Data) -> Result<()>
|
|||
|
||||
let issues = find_issues(&log, data).await?;
|
||||
|
||||
channel
|
||||
.send_message(ctx, |m| {
|
||||
m.reference_message(message)
|
||||
.allowed_mentions(|am| am.replied_user(true))
|
||||
.embed(|e| {
|
||||
e.title("Log analysis");
|
||||
let embed = {
|
||||
let mut e = CreateEmbed::new().title("Log analysis");
|
||||
|
||||
if issues.is_empty() {
|
||||
e.color(COLORS["green"]).field(
|
||||
"Analyze failed!",
|
||||
"No issues found automatically",
|
||||
false,
|
||||
);
|
||||
} else {
|
||||
e.color(COLORS["red"]);
|
||||
if issues.is_empty() {
|
||||
e = e.color(COLORS["green"]).field(
|
||||
"Analyze failed!",
|
||||
"No issues found automatically",
|
||||
false,
|
||||
);
|
||||
} else {
|
||||
e = e.color(COLORS["red"]);
|
||||
|
||||
for (title, description) in issues {
|
||||
e.field(title, description, false);
|
||||
}
|
||||
}
|
||||
for (title, description) in issues {
|
||||
e = e.field(title, description, false);
|
||||
}
|
||||
}
|
||||
|
||||
e
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
e
|
||||
};
|
||||
|
||||
let allowed_mentions = CreateAllowedMentions::new().replied_user(true);
|
||||
let message = CreateMessage::new()
|
||||
.allowed_mentions(allowed_mentions)
|
||||
.embed(embed);
|
||||
|
||||
channel.send_message(ctx, message).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ pub async fn handle(ctx: &Context, reaction: &Reaction) -> Result<()> {
|
|||
.wrap_err_with(|| "Couldn't fetch message from reaction!")?;
|
||||
|
||||
if let Some(interaction) = &message.interaction {
|
||||
if interaction.kind == InteractionType::ApplicationCommand
|
||||
if interaction.kind == InteractionType::Command
|
||||
&& interaction.user == user
|
||||
&& reaction.emoji.unicode_eq("❌")
|
||||
{
|
||||
|
|
|
@ -1,27 +1,20 @@
|
|||
use color_eyre::eyre::{eyre, Context as _, Result};
|
||||
use poise::serenity_prelude::{Context, Message};
|
||||
use color_eyre::eyre::Result;
|
||||
use poise::serenity_prelude::{Context, CreateAllowedMentions, CreateMessage, Message};
|
||||
|
||||
use crate::utils;
|
||||
|
||||
pub async fn handle(ctx: &Context, message: &Message) -> Result<()> {
|
||||
let embeds = utils::resolve_message(ctx, message).await?;
|
||||
|
||||
// TOOD getchoo: actually reply to user
|
||||
// TODO getchoo: actually reply to user
|
||||
// ...not sure why Message doesn't give me a builder in reply() or equivalents
|
||||
let our_channel = message
|
||||
.channel(ctx)
|
||||
.await
|
||||
.wrap_err_with(|| "Couldn't get channel from message!")?
|
||||
.guild()
|
||||
.ok_or_else(|| eyre!("Couldn't convert to GuildChannel!"))?;
|
||||
|
||||
if !embeds.is_empty() {
|
||||
our_channel
|
||||
.send_message(ctx, |m| {
|
||||
m.set_embeds(embeds)
|
||||
.allowed_mentions(|am| am.replied_user(false))
|
||||
})
|
||||
.await?;
|
||||
let allowed_mentions = CreateAllowedMentions::new().replied_user(false);
|
||||
let reply = CreateMessage::new()
|
||||
.embeds(embeds)
|
||||
.allowed_mentions(allowed_mentions);
|
||||
|
||||
message.channel_id.send_message(ctx, reply).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -2,8 +2,8 @@ use crate::{api, Data};
|
|||
|
||||
use color_eyre::eyre::{Report, Result};
|
||||
use log::*;
|
||||
use poise::serenity_prelude::{Activity, Context, OnlineStatus};
|
||||
use poise::{Event, FrameworkContext};
|
||||
use poise::serenity_prelude::{ActivityData, Context, FullEvent, OnlineStatus};
|
||||
use poise::FrameworkContext;
|
||||
|
||||
mod analyze_logs;
|
||||
mod delete_on_reaction;
|
||||
|
@ -14,22 +14,22 @@ mod support_onboard;
|
|||
|
||||
pub async fn handle(
|
||||
ctx: &Context,
|
||||
event: &Event<'_>,
|
||||
event: &FullEvent,
|
||||
_framework: FrameworkContext<'_, Data, Report>,
|
||||
data: &Data,
|
||||
) -> Result<()> {
|
||||
match event {
|
||||
Event::Ready { data_about_bot } => {
|
||||
FullEvent::Ready { data_about_bot } => {
|
||||
info!("Logged in as {}!", data_about_bot.user.name);
|
||||
|
||||
let latest_minecraft_version = api::prism_meta::get_latest_minecraft_version().await?;
|
||||
let activity = Activity::playing(format!("Minecraft {}", latest_minecraft_version));
|
||||
let activity = ActivityData::playing(format!("Minecraft {}", latest_minecraft_version));
|
||||
|
||||
info!("Setting presence to activity {activity:#?}");
|
||||
ctx.set_presence(Some(activity), OnlineStatus::Online).await;
|
||||
ctx.set_presence(Some(activity), OnlineStatus::Online);
|
||||
}
|
||||
|
||||
Event::Message { new_message } => {
|
||||
FullEvent::Message { new_message } => {
|
||||
// ignore new messages from bots
|
||||
// NOTE: the webhook_id check allows us to still respond to PK users
|
||||
if new_message.author.bot && new_message.webhook_id.is_none() {
|
||||
|
@ -52,11 +52,13 @@ pub async fn handle(
|
|||
analyze_logs::handle(ctx, new_message, data).await?;
|
||||
}
|
||||
|
||||
Event::ReactionAdd { add_reaction } => {
|
||||
delete_on_reaction::handle(ctx, add_reaction).await?
|
||||
FullEvent::ReactionAdd { add_reaction } => {
|
||||
delete_on_reaction::handle(ctx, add_reaction).await?;
|
||||
}
|
||||
|
||||
Event::ThreadCreate { thread } => support_onboard::handle(ctx, thread).await?,
|
||||
FullEvent::ThreadCreate { thread } => {
|
||||
support_onboard::handle(ctx, thread).await?;
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
use color_eyre::eyre::{eyre, Result};
|
||||
use log::*;
|
||||
use poise::serenity_prelude::{ChannelType, Context, GuildChannel};
|
||||
use poise::serenity_prelude::{
|
||||
ChannelType, Context, CreateAllowedMentions, CreateMessage, GuildChannel,
|
||||
};
|
||||
|
||||
pub async fn handle(ctx: &Context, thread: &GuildChannel) -> Result<()> {
|
||||
if thread.kind != ChannelType::PublicThread {
|
||||
debug!("Not doing support onboard in non-thread channel");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let parent_id = thread
|
||||
if thread
|
||||
.parent_id
|
||||
.ok_or_else(|| eyre!("Couldn't get parent ID from thread {}!", thread.name))?;
|
||||
|
||||
let parent_channel = ctx
|
||||
.cache
|
||||
.guild_channel(parent_id)
|
||||
.ok_or_else(|| eyre!("Couldn't get GuildChannel {}!", parent_id))?;
|
||||
|
||||
if parent_channel.name != "support" {
|
||||
.ok_or_else(|| eyre!("Couldn't get parent ID from thread {}!", thread.name))?
|
||||
.name(ctx)
|
||||
.await
|
||||
.unwrap_or("".to_string())
|
||||
!= "support"
|
||||
{
|
||||
debug!("Not posting onboarding message to threads outside of support");
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -32,12 +33,15 @@ pub async fn handle(ctx: &Context, thread: &GuildChannel) -> Result<()> {
|
|||
"Please don't ping people for support questions, unless you have their permission."
|
||||
);
|
||||
|
||||
thread
|
||||
.send_message(ctx, |m| {
|
||||
m.content(msg)
|
||||
.allowed_mentions(|am| am.replied_user(true).users(Vec::from([owner])))
|
||||
})
|
||||
.await?;
|
||||
let allowed_mentions = CreateAllowedMentions::new()
|
||||
.replied_user(true)
|
||||
.users(Vec::from([owner]));
|
||||
|
||||
let message = CreateMessage::new()
|
||||
.content(msg)
|
||||
.allowed_mentions(allowed_mentions);
|
||||
|
||||
thread.send_message(ctx, message).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
26
src/main.rs
26
src/main.rs
|
@ -10,8 +10,6 @@ use poise::{
|
|||
serenity_prelude as serenity, EditTracker, Framework, FrameworkOptions, PrefixFrameworkOptions,
|
||||
};
|
||||
|
||||
use serenity::ShardManager;
|
||||
|
||||
use redis::ConnectionLike;
|
||||
|
||||
use tokio::signal::ctrl_c;
|
||||
|
@ -19,7 +17,6 @@ use tokio::signal::ctrl_c;
|
|||
use tokio::signal::unix::{signal, SignalKind};
|
||||
#[cfg(target_family = "windows")]
|
||||
use tokio::signal::windows::ctrl_close;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
mod api;
|
||||
mod commands;
|
||||
|
@ -78,9 +75,9 @@ async fn setup(
|
|||
Ok(data)
|
||||
}
|
||||
|
||||
async fn handle_shutdown(shard_manager: Arc<Mutex<ShardManager>>, reason: &str) {
|
||||
async fn handle_shutdown(shard_manager: Arc<serenity::ShardManager>, reason: &str) {
|
||||
warn!("{reason}! Shutting down bot...");
|
||||
shard_manager.lock().await.shutdown_all().await;
|
||||
shard_manager.shutdown_all().await;
|
||||
println!("{}", "Everything is shutdown. Goodbye!".green())
|
||||
}
|
||||
|
||||
|
@ -111,7 +108,9 @@ async fn main() -> Result<()> {
|
|||
|
||||
prefix_options: PrefixFrameworkOptions {
|
||||
prefix: Some("r".into()),
|
||||
edit_tracker: Some(EditTracker::for_timespan(Duration::from_secs(3600))),
|
||||
edit_tracker: Some(Arc::from(EditTracker::for_timespan(Duration::from_secs(
|
||||
3600,
|
||||
)))),
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
|
@ -119,22 +118,23 @@ async fn main() -> Result<()> {
|
|||
};
|
||||
|
||||
let framework = Framework::builder()
|
||||
.token(token)
|
||||
.intents(intents)
|
||||
.options(options)
|
||||
.setup(|ctx, ready, framework| Box::pin(setup(ctx, ready, framework)))
|
||||
.build()
|
||||
.await
|
||||
.wrap_err_with(|| "Failed to build framework!")?;
|
||||
.build();
|
||||
|
||||
let mut client = serenity::ClientBuilder::new(token, intents)
|
||||
.framework(framework)
|
||||
.await?;
|
||||
|
||||
let shard_manager = client.shard_manager.clone();
|
||||
|
||||
let shard_manager = framework.shard_manager().clone();
|
||||
#[cfg(target_family = "unix")]
|
||||
let mut sigterm = signal(SignalKind::terminate())?;
|
||||
#[cfg(target_family = "windows")]
|
||||
let mut sigterm = ctrl_close()?;
|
||||
|
||||
tokio::select! {
|
||||
result = framework.start() => result.map_err(Report::from),
|
||||
result = client.start() => result.map_err(Report::from),
|
||||
_ = sigterm.recv() => {
|
||||
handle_shutdown(shard_manager, "Received SIGTERM").await;
|
||||
std::process::exit(0);
|
||||
|
|
|
@ -69,7 +69,7 @@ impl Storage {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn expire_key(&self, key: &str, expire_seconds: usize) -> Result<()> {
|
||||
async fn expire_key(&self, key: &str, expire_seconds: i64) -> Result<()> {
|
||||
debug!("Expiring key {key} in {expire_seconds}");
|
||||
|
||||
let mut con = self.client.get_async_connection().await?;
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use color_eyre::eyre::{eyre, Context as _, Result};
|
||||
use log::*;
|
||||
use once_cell::sync::Lazy;
|
||||
use poise::serenity_prelude::{ChannelType, Colour, Context, CreateEmbed, Message};
|
||||
use poise::serenity_prelude::{
|
||||
ChannelId, ChannelType, Colour, Context, CreateEmbed, CreateEmbedAuthor, CreateEmbedFooter,
|
||||
Message, MessageId,
|
||||
};
|
||||
use regex::Regex;
|
||||
|
||||
static MESSAGE_PATTERN: Lazy<Regex> = Lazy::new(|| {
|
||||
|
@ -21,103 +26,84 @@ pub fn find_first_image(msg: &Message) -> Option<String> {
|
|||
}
|
||||
|
||||
pub async fn resolve(ctx: &Context, msg: &Message) -> Result<Vec<CreateEmbed>> {
|
||||
let matches = MESSAGE_PATTERN.captures_iter(&msg.content);
|
||||
let matches = MESSAGE_PATTERN
|
||||
.captures_iter(&msg.content)
|
||||
.map(|capture| capture.extract());
|
||||
|
||||
let mut embeds: Vec<CreateEmbed> = vec![];
|
||||
|
||||
for captured in matches.take(3) {
|
||||
// don't leak messages from other servers
|
||||
if let Some(server_id) = captured.get(0) {
|
||||
let other_server: u64 = server_id.as_str().parse().unwrap_or_default();
|
||||
let current_id = msg.guild_id.unwrap_or_default();
|
||||
for (_, [_server_id, channel_id, message_id]) in matches {
|
||||
let channel = ChannelId::from_str(channel_id)
|
||||
.wrap_err_with(|| format!("Couldn't parse channel ID {channel_id}!"))?
|
||||
.to_channel_cached(ctx.as_ref())
|
||||
.ok_or_else(|| eyre!("Couldn't find Guild Channel from {channel_id}!"))?
|
||||
.to_owned();
|
||||
|
||||
if &other_server != current_id.as_u64() {
|
||||
debug!("Not resolving message of other guild.");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
warn!("Couldn't find server_id from Discord link! Not resolving message to be safe");
|
||||
continue;
|
||||
}
|
||||
let author_can_view = if channel.kind == ChannelType::PublicThread
|
||||
|| channel.kind == ChannelType::PrivateThread
|
||||
{
|
||||
let thread_members = channel
|
||||
.id
|
||||
.get_thread_members(ctx)
|
||||
.await
|
||||
.wrap_err("Couldn't get members from thread!")?;
|
||||
|
||||
if let Some(channel_id) = captured.get(1) {
|
||||
let parsed: u64 = channel_id.as_str().parse().unwrap_or_default();
|
||||
let req_channel = ctx
|
||||
.cache
|
||||
.channel(parsed)
|
||||
.ok_or_else(|| eyre!("Couldn't get channel_id from Discord regex!"))?
|
||||
.guild()
|
||||
.ok_or_else(|| {
|
||||
eyre!("Couldn't convert to GuildChannel from channel_id {parsed}!")
|
||||
})?;
|
||||
|
||||
if !req_channel.is_text_based() {
|
||||
debug!("Not resolving message is non-text-based channel.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if req_channel.kind == ChannelType::PrivateThread {
|
||||
if let Some(id) = req_channel.parent_id {
|
||||
let parent = ctx.cache.guild_channel(id).ok_or_else(|| {
|
||||
eyre!("Couldn't get parent channel {id} for thread {req_channel}!")
|
||||
})?;
|
||||
let parent_members = parent.members(ctx).await.unwrap_or_default();
|
||||
|
||||
if !parent_members.iter().any(|m| m.user.id == msg.author.id) {
|
||||
debug!("Not resolving message for user not a part of a private thread.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if req_channel
|
||||
.members(ctx)
|
||||
.await?
|
||||
thread_members
|
||||
.iter()
|
||||
.any(|m| m.user.id == msg.author.id)
|
||||
{
|
||||
debug!("Not resolving for message for user not a part of a channel");
|
||||
continue;
|
||||
}
|
||||
.any(|member| member.user_id == msg.author.id)
|
||||
} else {
|
||||
channel
|
||||
.members(ctx)
|
||||
.wrap_err_with(|| format!("Couldn't get members for channel {channel_id}!"))?
|
||||
.iter()
|
||||
.any(|member| member.user.id == msg.author.id)
|
||||
};
|
||||
|
||||
let message_id: u64 = captured
|
||||
.get(2)
|
||||
.ok_or_else(|| eyre!("Couldn't get message_id from Discord regex!"))?
|
||||
.as_str()
|
||||
.parse()
|
||||
.wrap_err_with(|| {
|
||||
eyre!("Couldn't parse message_id from Discord regex as a MessageId!")
|
||||
})?;
|
||||
|
||||
let original_message = req_channel.message(ctx, message_id).await?;
|
||||
let mut embed = CreateEmbed::default();
|
||||
embed
|
||||
.author(|a| {
|
||||
a.name(original_message.author.tag())
|
||||
.icon_url(original_message.author.default_avatar_url())
|
||||
})
|
||||
.color(Colour::BLITZ_BLUE)
|
||||
.timestamp(original_message.timestamp)
|
||||
.footer(|f| f.text(format!("#{}", req_channel.name)))
|
||||
.description(format!(
|
||||
"{}\n\n[Jump to original message]({})",
|
||||
original_message.content,
|
||||
original_message.link()
|
||||
));
|
||||
|
||||
if !original_message.attachments.is_empty() {
|
||||
embed.fields(original_message.attachments.iter().map(|a| {
|
||||
(
|
||||
"Attachments".to_string(),
|
||||
format!("[{}]({})", a.filename, a.url),
|
||||
false,
|
||||
)
|
||||
}));
|
||||
|
||||
if let Some(image) = find_first_image(msg) {
|
||||
embed.image(image);
|
||||
}
|
||||
}
|
||||
|
||||
embeds.push(embed);
|
||||
if !author_can_view {
|
||||
debug!("Not resolving message for author who can't see it");
|
||||
}
|
||||
|
||||
let original_message = channel
|
||||
.message(
|
||||
ctx,
|
||||
MessageId::from_str(message_id)
|
||||
.wrap_err_with(|| format!("Couldn't parse message ID {message_id}!"))?,
|
||||
)
|
||||
.await
|
||||
.wrap_err_with(|| {
|
||||
format!("Couldn't get message from ID {message_id} in channel {channel_id}!")
|
||||
})?;
|
||||
|
||||
let author = CreateEmbedAuthor::new(original_message.author.tag())
|
||||
.icon_url(original_message.author.default_avatar_url());
|
||||
let footer = CreateEmbedFooter::new(format!("#{}", channel.name));
|
||||
|
||||
let mut embed = CreateEmbed::new()
|
||||
.author(author)
|
||||
.color(Colour::BLITZ_BLUE)
|
||||
.timestamp(original_message.timestamp)
|
||||
.footer(footer)
|
||||
.description(format!(
|
||||
"{}\n\n[Jump to original message]({})",
|
||||
original_message.content,
|
||||
original_message.link()
|
||||
));
|
||||
|
||||
if !original_message.attachments.is_empty() {
|
||||
embed = embed.fields(original_message.attachments.iter().map(|a| {
|
||||
(
|
||||
"Attachments".to_string(),
|
||||
format!("[{}]({})", a.filename, a.url),
|
||||
false,
|
||||
)
|
||||
}));
|
||||
|
||||
if let Some(image) = find_first_image(msg) {
|
||||
embed = embed.image(image);
|
||||
}
|
||||
}
|
||||
|
||||
embeds.push(embed);
|
||||
}
|
||||
|
||||
Ok(embeds)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue