Skip to content

Commit 36d338e

Browse files
authored
Merge pull request #41 from AltF02/buttons
Add buttons instead of reactions
2 parents 051e93a + b46cdf3 commit 36d338e

File tree

8 files changed

+146
-112
lines changed

8 files changed

+146
-112
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ features = ["colored"]
2727

2828
[dependencies.serenity]
2929
version = "0.11"
30-
features = ["framework", "standard_framework", "rustls_backend", "cache", "collector", "utils", "unstable_discord_api", "chrono"]
30+
features = ["framework", "standard_framework", "rustls_backend", "cache", "collector", "utils", "unstable_discord_api", "chrono", "model"]
3131

3232
[dependencies.tokio]
3333
version = "1"

src/bot.rs

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use std::collections::HashSet;
2222
use std::sync::Arc;
2323

2424
mod commands;
25+
pub mod components;
2526
pub mod embeds;
2627
mod events;
2728
mod hooks;

src/bot/components.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use crate::models::launch::LaunchID;
2+
use serenity::builder::{CreateActionRow, CreateButton, CreateComponents};
3+
use serenity::model::prelude::message_component::ButtonStyle;
4+
5+
pub struct RemindComponent<'a> {
6+
launch_id: &'a LaunchID,
7+
}
8+
9+
impl<'a> RemindComponent<'a> {
10+
pub fn new(launch_id: &'a LaunchID) -> RemindComponent {
11+
Self { launch_id }
12+
}
13+
14+
fn button(&self) -> CreateButton {
15+
let mut b = CreateButton::default();
16+
b.custom_id(self.launch_id);
17+
b.label("Remind Me");
18+
b.style(ButtonStyle::Primary);
19+
b
20+
}
21+
22+
fn action_row(&self) -> CreateActionRow {
23+
let mut ar = CreateActionRow::default();
24+
ar.add_button(self.button());
25+
ar
26+
}
27+
}
28+
29+
pub fn create_basic_components() -> CreateComponents {
30+
CreateComponents::default()
31+
}
32+
33+
pub fn create_launch_components(launch_id: &LaunchID) -> CreateComponents {
34+
let mut c = create_basic_components();
35+
36+
let rc = RemindComponent::new(launch_id);
37+
c.add_action_row(rc.action_row());
38+
c
39+
}

src/bot/events.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
mod guild_create;
2-
mod reaction_add;
2+
mod interaction_create;
33
mod ready;
44

55
use crate::bot::loops::launches_loop;
66

77
use crate::bot::events::guild_create::GuildCreateEvent;
8-
use crate::bot::events::reaction_add::ReactionAddEvent;
8+
use crate::bot::events::interaction_create::InteractionCreateEvent;
99
use crate::bot::events::ready::ReadyEvent;
1010
use log::info;
1111
use serenity::{async_trait, model::prelude::*, prelude::*};
@@ -27,10 +27,6 @@ impl EventHandler for Handler {
2727
GuildCreateEvent::run(&ctx, &guild, &is_new).await;
2828
}
2929

30-
async fn reaction_add(&self, ctx: Context, reaction: Reaction) {
31-
ReactionAddEvent::run(&ctx, &reaction).await;
32-
}
33-
3430
async fn ready(&self, ctx: Context, ready: Ready) {
3531
ReadyEvent::run(&ctx, &ready).await;
3632

@@ -47,4 +43,8 @@ impl EventHandler for Handler {
4743
*self.run_loops.lock().await = false;
4844
}
4945
}
46+
47+
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
48+
InteractionCreateEvent::run(&ctx, interaction).await;
49+
}
5050
}

src/bot/events/interaction_create.rs

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use crate::extensions::ClientContextExt;
2+
use anyhow::Result;
3+
use log::error;
4+
use serenity::client::Context;
5+
use serenity::model::interactions::InteractionResponseType;
6+
use serenity::model::prelude::message_component::ComponentType;
7+
use serenity::model::prelude::{Interaction, InteractionApplicationCommandCallbackDataFlags};
8+
9+
pub struct InteractionCreateEvent;
10+
11+
impl InteractionCreateEvent {
12+
pub async fn run(ctx: &Context, interaction: Interaction) -> Result<()> {
13+
let db = ctx.get_db().await;
14+
let mc = interaction.message_component();
15+
16+
if mc.is_none() {
17+
return Ok(());
18+
}
19+
20+
let component = mc.unwrap();
21+
22+
if component.data.component_type != ComponentType::Button
23+
|| component.message.embeds.is_empty()
24+
{
25+
return Ok(());
26+
}
27+
28+
let reminder =
29+
sqlx::query("SELECT * FROM astra.reminders WHERE user_id = $1 AND launch_id = $2")
30+
.bind(component.user.id.0 as i64)
31+
.bind(&component.data.custom_id)
32+
.fetch_optional(&db.pool)
33+
.await;
34+
35+
if let Err(e) = reminder {
36+
error!("Failed to query, {:?}", e);
37+
return Ok(());
38+
}
39+
40+
let reminder_exists = reminder.unwrap().is_some();
41+
42+
let launch_name = component.message.embeds[0].title.as_ref().unwrap();
43+
44+
let mut content = if reminder_exists {
45+
format!("I will stop reminding you for **{}**", launch_name)
46+
} else {
47+
format!("I will remind you for **{}**! If you want me to stop from reminding you, hit the button again", launch_name)
48+
};
49+
50+
let dm_channel = component.user.create_dm_channel(&ctx).await;
51+
52+
if dm_channel.is_err() {
53+
content = String::from("Your DM's are closed, please open them and try again.");
54+
} else {
55+
let query = if reminder_exists {
56+
"DELETE FROM astra.reminders WHERE user_id = $1 AND launch_id = $2"
57+
} else {
58+
"INSERT INTO astra.reminders (user_id, launch_id) VALUES ($1, $2)"
59+
};
60+
61+
sqlx::query(query)
62+
.bind(component.user.id.0 as i64)
63+
.bind(&component.data.custom_id)
64+
.execute(&db.pool)
65+
.await?;
66+
}
67+
68+
component
69+
.create_interaction_response(&ctx, |r| {
70+
r.kind(InteractionResponseType::ChannelMessageWithSource);
71+
r.interaction_response_data(|d| {
72+
d.content(content);
73+
d.flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL)
74+
});
75+
r
76+
})
77+
.await?;
78+
79+
Ok(())
80+
}
81+
}

src/bot/events/reaction_add.rs

-96
This file was deleted.

src/bot/loops/launches.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use chrono::{DateTime, Utc};
88

99
use log::warn;
1010

11-
use serenity::model::channel::ReactionType::Unicode;
1211
use serenity::prelude::Context;
1312
use std::error::Error;
1413
use std::sync::Arc;
@@ -21,7 +20,7 @@ pub async fn dispatch_to_guilds(
2120
) -> Result<(), Box<dyn Error>> {
2221
let guilds = db.get_guilds_queried(true, Query::Launches).await;
2322

24-
let remaining_str = (dt - chrono::offset::Utc::now()).create_24h();
23+
let remaining_str = (dt - Utc::now()).create_24h();
2524
for guild in guilds {
2625
let channel = match guild.channel_id.fetch(ctx).await {
2726
Some(channel) => channel,
@@ -30,9 +29,11 @@ pub async fn dispatch_to_guilds(
3029
}
3130
};
3231

33-
if let Ok(m) = channel.send_launch(ctx, next_launch, &remaining_str).await {
34-
m.react(&ctx, Unicode("🔔".to_string())).await?;
35-
} else {
32+
if channel
33+
.send_launch(ctx, next_launch, &remaining_str)
34+
.await
35+
.is_err()
36+
{
3637
warn!("Failed to send Launch to {}", channel.id());
3738
}
3839
}
@@ -67,10 +68,10 @@ pub async fn check_future_launch(ctx: Arc<Context>) -> Result<(), Box<dyn Error>
6768
}
6869
}
6970

70-
let mut dblaunch = DBLaunch::from(next_launch);
71-
dblaunch.dispatched = dispatched;
71+
let mut db_launch = DBLaunch::from(next_launch);
72+
db_launch.dispatched = dispatched;
7273

73-
db.set_launch(dblaunch).await?;
74+
db.set_launch(db_launch).await?;
7475
}
7576

7677
Ok(())

src/extensions/channel.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::bot::components::create_launch_components;
12
use crate::bot::embeds::{create_apod_embed, create_basic_embed, create_launch_embed};
23
use crate::models::apod::Apod;
34
use crate::models::launch::Launch;
@@ -37,8 +38,15 @@ impl ChannelExt for Channel {
3738

3839
async fn send_launch(&self, ctx: &client::Context, n: &Launch, r: &String) -> Result<Message> {
3940
let e = create_launch_embed(n, r);
41+
let c = create_launch_components(&n.id);
4042

41-
self.id().send_message(ctx, move |m| m.set_embed(e)).await
43+
self.id()
44+
.send_message(ctx, move |m| {
45+
m.set_embed(e);
46+
m.set_components(c);
47+
m
48+
})
49+
.await
4250
}
4351

4452
async fn send_apod(&self, ctx: &client::Context, n: &Apod) -> Result<Message> {

0 commit comments

Comments
 (0)