use poise::serenity_prelude::{self as serenity, Interaction, MessageComponentInteraction, MessageId, ChannelId};
use regex::Regex;
use serde_json::json;
use crate::models::*;
use crate::{Data, Error};
use tracing::info;
/**
* Handles specific events, including ReactionAdd, which is needed for the reaction role handler to
* function properly
*/
pub async fn event_handler(
ctx: &serenity::Context,
event: &poise::Event<'_>,
data: &Data,
) -> Result<(), Error> {
{
let pool = data.pg.lock().unwrap().clone();
match event {
poise::Event::ReactionAdd { add_reaction } => {
let current_user = ctx.http.get_current_user().await?;
if add_reaction.user_id.unwrap() == current_user.id {
return Ok(());
}
// This fetches the role and lets us query extra data including role ID
let rrole = sqlx::query_as!(
ReactionRole,
"SELECT * FROM reaction_roles WHERE message_id=$1 AND reaction=$2",
add_reaction.message_id.0.to_string(),
add_reaction.emoji.to_string()
)
.fetch_one(&pool)
.await?;
let member = ctx
.http
.get_member(
rrole.guild_id.parse::<u64>()?,
add_reaction.user_id.unwrap().0,
)
.await?;
// Honestly, not really needed.
let member_roles = member.roles;
let role_id = serenity::RoleId(rrole.role_id.parse::<u64>()?);
if member_roles.contains(&role_id) {
ctx.http
.remove_member_role(
member.guild_id.0,
member.user.id.0,
role_id.0,
Some("Reaction Role Menu"),
)
.await?;
} else {
ctx.http
.add_member_role(
rrole.guild_id.parse::<u64>()?,
add_reaction.user_id.unwrap().0,
rrole.role_id.parse::<u64>()?,
Some("Reaction Role"),
)
.await?;
}
if let Ok(dm_chan) = add_reaction
.user_id
.unwrap()
.create_dm_channel(&ctx.http)
.await {
dm_chan.say(ctx, format!("Toggled the role!")).await?;
} else {
info!("Could not DM user, but we did the role anyways");
}
add_reaction.delete(&ctx.http).await?;
},
poise::Event::Message { new_message } => {
let current_user = ctx.http.get_current_user().await?;
if new_message.author.id.0 != current_user.id.0 {
// This message does *not* belong to the bot
let filters = sqlx::query_as::<_, MessageFilter>(
"SELECT * FROM message_filter WHERE guild_id=$1")
.bind(new_message.guild_id.unwrap().0.to_string())
.fetch_all(&pool)
.await?;
let content = new_message.content.clone();
for f in filters {
let r = Regex::new(&f.pattern)?;
if r.is_match(&content) {
match f.action {
FilterAction::Review => {
if let Ok(c) = sqlx::query_as!(ConfigChannel, "SELECT * FROM channels WHERE purpose='review' AND guild_id=$1", new_message.guild_id.unwrap().0.to_string())
.fetch_one(&pool)
.await {
let chan = serenity::ChannelId(c.channel_id.parse::<u64>()?);
chan.send_message(&ctx, |m| {
m.content(format!("Message was flagged for review (using rule {})", f.id));
m.components(|c| {
c.create_action_row(|r| {
r.create_button(|b| {
b.style(serenity::ButtonStyle::Primary);
b.label("Approve");
b.custom_id("approve");
b
});
r.create_button(|b| {
b.style(serenity::ButtonStyle::Danger);
b.label("Deny");
b.custom_id("deny");
b
});
r
});
c
});
m.embed(|e| {
e.author(|a| {
a.name(new_message.clone().author.name);
a.icon_url(new_message.clone().author.face())
});
e.description(content.clone());
e.footer(|f| {
f.text(format!("{}:{}", new_message.channel_id.0, new_message.id.0.to_string()))
});
e.field("Link", new_message.link().clone(), true)
})
}).await?;
} else {
let guild = new_message.guild(&ctx).unwrap();
let owner = guild.owner_id;
let dm_chan = owner.create_dm_channel(&ctx.http).await?;
dm_chan.say(&ctx.http, format!("Hi! I tried to flag a message for review in {}, but you haven't set a review channel yet! Set one now by running `filter channel` in the server.", guild.name.clone())).await?;
}
},
FilterAction::Delete => {
new_message.delete(&ctx.http).await?;
}
}
}
}
}
},
poise::Event::InteractionCreate { interaction } => {
match interaction {
Interaction::MessageComponent(mci) => {
let data = &mci.data;
let mci2 = mci.clone();
match data.custom_id.as_str() {
"approve" => {
let msg_report = mci2.message.clone();
let footer = msg_report.embeds[0].clone().footer.unwrap().text;
let mut footer = footer.split(':');
let orig_channel_id = footer.next().unwrap();
let orig_msg_id = footer.next().unwrap();
let orig_msg_id = MessageId(orig_msg_id.parse::<u64>()?);
let orig_channel_id = ChannelId(orig_channel_id.parse::<u64>()?);
let orig_msg = ctx.http.get_message(orig_channel_id.0, orig_msg_id.0).await?;
disable_buttons(&ctx, mci2).await?;
},
"deny" => {
let msg_report = mci2.message.clone();
let footer = msg_report.embeds[0].clone().footer.unwrap().text;
let mut footer = footer.split(':');
let orig_channel_id = footer.next().unwrap();
let orig_msg_id = footer.next().unwrap();
let orig_msg_id = MessageId(orig_msg_id.parse::<u64>()?);
let orig_channel_id = ChannelId(orig_channel_id.parse::<u64>()?);
let orig_msg = ctx.http.get_message(orig_channel_id.0, orig_msg_id.0).await?;
orig_msg.delete(&ctx).await?;
disable_buttons(&ctx, mci2).await?;
},
_ => (),
};
},
_ => ()
};
},
_ => (),
}
}
Ok(())
}
async fn disable_buttons(ctx: &serenity::Context, mut mci: MessageComponentInteraction) -> Result<(), Error> {
mci.message.edit(&ctx, |m| {
m.components(|c| {
c.create_action_row(|r| {
r.create_button(|b| {
b.style(serenity::ButtonStyle::Primary);
b.label("Approve");
b.custom_id("approve");
b.disabled(true);
b
});
r.create_button(|b| {
b.style(serenity::ButtonStyle::Danger);
b.label("Deny");
b.custom_id("deny");
b.disabled(true);
b
});
r
});
c
});
m
}).await?;
ctx.http.create_interaction_response(mci.id.0, &mci.token, &json!({ "type": 7})).await?;
Ok(())
}