Skip to content

Commit

Permalink
Merge pull request #37 from lajp/main
Browse files Browse the repository at this point in the history
fix: duplicate notifications and /poistavahti
  • Loading branch information
lajp authored Jan 9, 2024
2 parents 2c9741f + 7d7ebf4 commit c139d54
Show file tree
Hide file tree
Showing 11 changed files with 957 additions and 784 deletions.
1,173 changes: 633 additions & 540 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ huutonet = []

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies.serenity]
version = "0.11"
version = "0.12"
default-features = false
features = ["client", "gateway", "rustls_backend", "model"]

Expand Down
167 changes: 100 additions & 67 deletions src/command/discord/interaction.rs
Original file line number Diff line number Diff line change
@@ -1,41 +1,34 @@
use itertools::Itertools;
use serenity::builder::CreateComponents;
use serenity::model::application::interaction::{Interaction, InteractionResponseType};
use serenity::all::ComponentInteractionDataKind;
use serenity::builder::{
CreateActionRow, CreateSelectMenu, CreateSelectMenuOption, EditInteractionResponse,
};
use serenity::model::application::Interaction;
use serenity::prelude::*;

use super::extensions::ClientContextExt;

pub fn menu_from_options<'a>(
components: &'a mut CreateComponents,
custom_id: &'a str,
pub fn menu_from_options(
custom_id: &str,
options: Vec<(impl ToString, impl ToString)>,
) -> &'a mut CreateComponents {
components.create_action_row(|r| {
r.create_select_menu(|m| {
m.custom_id(custom_id);
m.options(|o| {
for (label, value) in &options {
o.create_option(|oo| {
oo.label(&label.to_string());
oo.value(&value.to_string())
});
}
o
})
})
})
) -> Vec<CreateActionRow> {
let menu_options = options
.iter()
.map(|(l, v)| CreateSelectMenuOption::new(l.to_string(), v.to_string()))
.collect::<Vec<_>>();
let menu = CreateSelectMenu::new(
custom_id,
serenity::builder::CreateSelectMenuKind::String {
options: menu_options,
},
);
vec![CreateActionRow::SelectMenu(menu)]
}

pub async fn handle_interaction(ctx: Context, interaction: Interaction) {
match interaction {
Interaction::ApplicationCommand(command) => {
command
.create_interaction_response(&ctx.http, |response| {
response.interaction_response_data(|d| d.ephemeral(true));
response.kind(InteractionResponseType::DeferredChannelMessageWithSource)
})
.await
.unwrap();
Interaction::Command(command) => {
command.defer_ephemeral(&ctx.http).await.unwrap();

let content = match command.data.name.as_str() {
"vahti" => super::vahti::run(&ctx, &command).await,
Expand All @@ -46,23 +39,14 @@ pub async fn handle_interaction(ctx: Context, interaction: Interaction) {

if !content.is_empty() {
command
.edit_original_interaction_response(&ctx.http, |message| {
message.content(&content)
})
.edit_response(&ctx.http, EditInteractionResponse::new().content(&content))
.await
.unwrap();
}
}
Interaction::MessageComponent(button) => {
button
.create_interaction_response(&ctx.http, |response| {
response.interaction_response_data(|d| d.ephemeral(true));
response.kind(InteractionResponseType::DeferredChannelMessageWithSource)
})
.await
.unwrap();

Interaction::Component(button) => {
if button.data.custom_id == "remove_vahti" {
button.defer_ephemeral(&ctx.http).await.unwrap();
let message = button.message.clone();
let urls: Vec<_> = message
.embeds
Expand All @@ -73,25 +57,24 @@ pub async fn handle_interaction(ctx: Context, interaction: Interaction) {

if !urls.is_empty() {
button
.edit_original_interaction_response(&ctx.http, |m| {
m.components(|c| {
menu_from_options(
c,
"remove_vahti_menu",
urls.iter().zip(urls.iter()).collect::<Vec<_>>(),
)
})
})
.edit_response(
&ctx.http,
EditInteractionResponse::new().components(menu_from_options(
"remove_vahti_menu",
urls.iter().zip(urls.iter()).collect::<Vec<_>>(),
)),
)
.await
.unwrap();
} else {
button
.edit_original_interaction_response(&ctx.http, |m| {
m.content("Creating Vahti deletion menu failed, try deleting the Vahti manually with /poistavahti")
})
.edit_response(&ctx.http,
EditInteractionResponse::new().content("Creating Vahti deletion menu failed, try deleting the Vahti manually with /poistavahti")
)
.await.unwrap();
}
} else if button.data.custom_id == "block_seller" {
button.defer_ephemeral(&ctx.http).await.unwrap();
let message = button.message.clone();

let urls: Vec<_> = message
Expand Down Expand Up @@ -132,52 +115,102 @@ pub async fn handle_interaction(ctx: Context, interaction: Interaction) {
.collect::<Vec<_>>();

button
.edit_original_interaction_response(&ctx.http, |m| {
m.content("Choose the seller to block");
m.components(|c| menu_from_options(c, "block_seller_menu", sellers))
})
.edit_response(
&ctx.http,
EditInteractionResponse::new()
.content("Choose the seller to block")
.components(menu_from_options("block_seller_menu", sellers)),
)
.await
.unwrap();
} else if button.data.custom_id == "unblock_seller" {
button.defer_ephemeral(&ctx.http).await.unwrap();
let db = ctx.get_db().await.unwrap();
let userid = button.user.id.0;
let ids: Vec<&str> = button.data.values[0].split(',').collect();
let userid = u64::from(button.user.id);
let ids: Vec<String> = match button.data.kind.clone() {
ComponentInteractionDataKind::StringSelect { values } => {
values[0].split(',').map(|s| s.to_string()).collect()
}
_ => unreachable!(),
};
let sellerid = ids[0].parse::<i32>().unwrap();
let siteid = ids[1].parse::<i32>().unwrap();

db.remove_seller_from_blacklist(userid.try_into().unwrap(), sellerid, siteid)
.await
.unwrap();
button
.edit_original_interaction_response(&ctx.http, |m| m.content("Esto poistettu!"))
.edit_response(
&ctx.http,
EditInteractionResponse::new().content("Esto poistettu!"),
)
.await
.unwrap();
} else if button.data.custom_id == "remove_vahti_menu" {
let userid = button.user.id.0;
let url = button.data.values[0].to_string();
button.defer_ephemeral(&ctx.http).await.unwrap();
let userid = u64::from(button.user.id);
let url = match button.data.kind.clone() {
ComponentInteractionDataKind::StringSelect { values } => values[0].to_string(),
_ => unreachable!(),
};
let db = ctx.get_db().await.unwrap();

crate::vahti::remove_vahti(db, &url, userid, crate::delivery::discord::ID)
.await
.unwrap();
button
.edit_original_interaction_response(&ctx.http, |m| {
m.content(format!("Poistettu vahti: `{}`", url))
})
.edit_response(
&ctx.http,
EditInteractionResponse::new()
.content(format!("Poistettu vahti: `{}`", url)),
)
.await
.unwrap();
} else if button.data.custom_id.starts_with("remove_vahti_menu_page_") {
let page_number: usize = button
.data
.custom_id
.strip_prefix("remove_vahti_menu_page_")
.unwrap()
.parse()
.unwrap();

button
.create_response(
&ctx.http,
serenity::builder::CreateInteractionResponse::UpdateMessage(
super::poistavahti::update_message(
&ctx,
page_number,
u64::from(button.user.id),
)
.await,
),
)
.await
.unwrap();
return;
} else if button.data.custom_id == "block_seller_menu" {
button.defer_ephemeral(&ctx.http).await.unwrap();
let db = ctx.get_db().await.unwrap();
let userid = button.user.id.0;
let ids: Vec<&str> = button.data.values[0].split(',').collect();
let userid = u64::from(button.user.id);
let ids: Vec<String> = match button.data.kind.clone() {
ComponentInteractionDataKind::StringSelect { values } => {
values[0].split(',').map(|s| s.to_string()).collect()
}
_ => unreachable!(),
};
let sellerid = ids[0].parse::<i32>().unwrap();
let siteid = ids[1].parse::<i32>().unwrap();

db.add_seller_to_blacklist(userid as i64, sellerid, siteid)
.await
.unwrap();
button
.edit_original_interaction_response(&ctx.http, |m| m.content("Myyjä estetty!"))
.edit_response(
&ctx.http,
EditInteractionResponse::new().content("Myyjä estetty!"),
)
.await
.unwrap();
}
Expand Down
25 changes: 13 additions & 12 deletions src/command/discord/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ mod vahti;
use std::sync::Arc;

use async_trait::async_trait;
use serenity::client::bridge::gateway::ShardManager;
use serenity::model::application::command;
use serenity::model::application::interaction::Interaction;
use serenity::gateway::ShardManager;
use serenity::model::application::Interaction;
use serenity::model::gateway::GatewayIntents;
use serenity::model::prelude::*;
use serenity::prelude::*;
Expand All @@ -30,12 +29,14 @@ impl EventHandler for Handler {

async fn ready(&self, ctx: Context, ready: Ready) {
info!("Connected as {}", ready.user.name);

let _ = command::Command::create_global_application_command(&ctx.http, |command| {
vahti::register(command);
poistavahti::register(command);
poistaesto::register(command)
})
let _ = serenity::model::application::Command::set_global_commands(
&ctx.http,
vec![
vahti::register(),
poistavahti::register(),
poistaesto::register(),
],
)
.await;
}
async fn resume(&self, _: Context, _: ResumedEvent) {
Expand All @@ -48,7 +49,7 @@ pub struct Discord {
}

pub struct Manager {
shard_manager: Arc<Mutex<ShardManager>>,
shard_manager: Arc<ShardManager>,
}

impl Discord {
Expand All @@ -62,7 +63,7 @@ impl Discord {
.expect("Invalid APPLICATION_ID");

let client = Client::builder(&token, GatewayIntents::non_privileged())
.application_id(application_id)
.application_id(application_id.into())
.event_handler(Handler)
.await?;

Expand All @@ -78,7 +79,7 @@ impl Discord {
impl super::Manager for Manager {
async fn shutdown(&self) {
info!("Discord destroy");
self.shard_manager.lock().await.shutdown_all().await;
self.shard_manager.shutdown_all().await;
info!("Discord destroy done");
}
}
Expand Down
33 changes: 13 additions & 20 deletions src/command/discord/poistaesto.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
use serenity::builder::CreateApplicationCommand;
use serenity::builder::{CreateCommand, EditInteractionResponse};
use serenity::client::Context;
use serenity::model::prelude::interaction::application_command::ApplicationCommandInteraction;
use serenity::model::application::CommandInteraction;

use super::extensions::ClientContextExt;
use super::interaction::menu_from_options;

pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
command
.name("poistaesto")
.description("Salli aiemmin estetty myyjä")
pub fn register() -> CreateCommand {
CreateCommand::new("poistaesto").description("Salli aiemmin estetty myyjä")
}

pub async fn run(ctx: &Context, command: &ApplicationCommandInteraction) -> String {
pub async fn run(ctx: &Context, command: &CommandInteraction) -> String {
let db = ctx.get_db().await.unwrap();
let blacklist = db
.fetch_user_blacklist(command.user.id.0 as i64)
.fetch_user_blacklist(u64::from(command.user.id) as i64)
.await
.unwrap();

Expand All @@ -38,18 +36,13 @@ pub async fn run(ctx: &Context, command: &ApplicationCommandInteraction) -> Stri
.zip(blacklist.iter().map(|ids| format!("{},{}", ids.0, ids.1)))
.collect::<Vec<_>>();

command
.edit_original_interaction_response(&ctx.http, |message| {
message.content("Valitse poistettava(t) esto/estot");

if blacklist.is_empty() {
message.content("Ei estettyjä myyjiä!")
} else {
message.components(|c| menu_from_options(c, "unblock_seller", options))
}
})
.await
.unwrap();
let mut edit = EditInteractionResponse::new().content("Valitse poistettava(t) esto/estot");
if blacklist.is_empty() {
edit = edit.content("Ei estettyjä myyjiä!");
} else {
edit = edit.components(menu_from_options("unblock_seller", options));
}
command.edit_response(&ctx.http, edit).await.unwrap();

String::new()
}
Loading

0 comments on commit c139d54

Please sign in to comment.