Skip to content

Commit 1777f17

Browse files
committed
feat(server): add Discord role verificator
1 parent d23a9f6 commit 1777f17

4 files changed

Lines changed: 117 additions & 41 deletions

File tree

src/config.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ pub struct GeneralConfig {
119119
#[derive(Debug, Deserialize, Serialize)]
120120
pub struct DiscordConfig {
121121
pub token: Option<String>,
122-
pub admin_roles: Option<Vec<u64>>
122+
pub admin_roles: Option<Vec<u64>>,
123+
pub join_verify_role: Option<u64>
123124
}
124125

125126
// Process code
@@ -305,7 +306,8 @@ impl Default for MainConfig {
305306
},
306307
discord: DiscordConfig {
307308
token: None,
308-
admin_roles: None
309+
admin_roles: None,
310+
join_verify_role: None
309311
}
310312
}
311313
}

src/discord/actions/paginator.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,30 +56,30 @@ pub async fn base_paginator(
5656
.components(create_action_row(current_page, total_pages, false))
5757
).await?;
5858

59-
let interaction = ComponentInteractionCollector::new(&ctx)
59+
let collector = ComponentInteractionCollector::new(&ctx)
6060
.author_id(author_id)
6161
.message_id(message.id)
6262
.timeout(Duration::from_secs(35))
6363
.next()
6464
.await;
6565

66-
let mci = match interaction {
66+
let interaction = match collector {
6767
Some(i) => i,
6868
None => break,
6969
};
7070

71-
match mci.data.custom_id.as_str() {
71+
match interaction.data.custom_id.as_str() {
7272
"first" => current_page = 0,
7373
"prev" => if current_page > 0 { current_page -= 1 },
7474
"next" => if current_page < total_pages - 1 { current_page += 1 },
7575
"last" => current_page = total_pages - 1,
7676
_ => {
77-
mci.defer(&ctx).await?;
77+
interaction.defer(&ctx).await?;
7878
continue;
7979
}
8080
}
8181

82-
mci.create_response(
82+
interaction.create_response(
8383
&ctx,
8484
CreateInteractionResponse::UpdateMessage(
8585
CreateInteractionResponseMessage::new()
@@ -150,18 +150,18 @@ pub async fn player_paged_view(
150150
.components(make_components(false, current_page, total_pages))
151151
).await?;
152152

153-
let interaction = ComponentInteractionCollector::new(ctx)
153+
let collector = ComponentInteractionCollector::new(ctx)
154154
.author_id(author_id)
155155
.message_id(message.id)
156156
.timeout(Duration::from_secs(35))
157157
.await;
158158

159-
let mci = match interaction {
159+
let interaction = match collector {
160160
Some(i) => i,
161161
None => break,
162162
};
163163

164-
match mci.data.custom_id.as_str() {
164+
match interaction.data.custom_id.as_str() {
165165
"first" => current_page = 0,
166166
"prev" => if current_page > 0 { current_page -= 1 },
167167
"next" => if current_page < total_pages - 1 { current_page += 1 },
@@ -170,7 +170,7 @@ pub async fn player_paged_view(
170170
let start_time = Utc::now();
171171
let server_id = player_history[current_page].server_id;
172172

173-
mci.create_response(&ctx.http(), CreateInteractionResponse::UpdateMessage(
173+
interaction.create_response(&ctx.http(), CreateInteractionResponse::UpdateMessage(
174174
CreateInteractionResponseMessage::new().embed(create_loading_embed("fetching server from database"))
175175
)).await?;
176176

@@ -209,7 +209,7 @@ pub async fn player_paged_view(
209209
_ => continue,
210210
}
211211

212-
mci.create_response(
212+
interaction.create_response(
213213
&ctx.http(),
214214
CreateInteractionResponse::UpdateMessage(
215215
CreateInteractionResponseMessage::new()

src/discord/actions/server.rs

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
1-
use std::fmt::format;
21
use std::net::Ipv4Addr;
32
use std::str::FromStr;
43
use std::time::Duration;
54
use base64::Engine;
65
use base64::prelude::BASE64_STANDARD;
76
use chrono::{DateTime, Utc};
87
use futures::StreamExt;
9-
use poise::ReplyHandle;
10-
use serenity::all::{AutoArchiveDuration, ButtonStyle, ChannelType, ComponentInteraction, ComponentInteractionCollector, CreateActionRow, CreateAttachment, CreateButton, CreateEmbed, CreateInteractionResponse, CreateInteractionResponseMessage, CreateMessage, CreateThread, EditAttachments, EditInteractionResponse, EditMessage, Message};
8+
use serenity::all::{AutoArchiveDuration, ButtonStyle, ChannelType, ComponentInteraction, ComponentInteractionCollector, CreateActionRow, CreateAttachment, CreateButton, CreateEmbed, CreateInteractionResponse, CreateInteractionResponseMessage, CreateMessage, CreateThread, EditAttachments, EditInteractionResponse, EditMessage, Message, RoleId};
119
use crate::database::{ServerHistory, ServerInfo};
1210
use crate::discord::{create_base_embed, create_error_embed, create_loading_embed, Context, Error};
1311
use crate::discord::actions::paginator::base_paginator;
14-
use crate::logger;
12+
use crate::{config, logger};
1513
use crate::minecraft::{join, ping, query};
1614

1715
// TODO: Add error msgs
@@ -71,6 +69,10 @@ pub fn build_manage_server_action_row(disabled: bool, history: &ServerHistory) -
7169
.label("History")
7270
.style(ButtonStyle::Primary)
7371
.emoji('📖')
72+
.disabled(disabled),
73+
CreateButton::new("view_join")
74+
.label("Join Details")
75+
.style(ButtonStyle::Secondary)
7476
.disabled(disabled)
7577
]
7678
)
@@ -171,7 +173,7 @@ pub async fn create_one_server_action(
171173
}
172174

173175
message.edit(
174-
&ctx.serenity_context().http,
176+
&ctx.http(),
175177
response.clone().components(build_manage_server_action_row(false, &server_history))
176178
).await?;
177179

@@ -256,6 +258,60 @@ pub async fn handle_server_actions(
256258
// with paginator
257259
}
258260

261+
"view_join" => {
262+
let start_time = Utc::now();
263+
let cfg = config::MainConfig::get().ok();
264+
let required_role_id = cfg.and_then(|c| c.discord.join_verify_role).map(RoleId::new);
265+
266+
let has_permission = if let Some(role_id) = required_role_id {
267+
interaction.member.as_ref().map_or(false, |member| {
268+
member.roles.contains(&role_id)
269+
})
270+
} else {
271+
false
272+
};
273+
274+
if !has_permission {
275+
interaction.create_response(
276+
&ctx.http(),
277+
CreateInteractionResponse::Message(
278+
CreateInteractionResponseMessage::new()
279+
.embed(
280+
create_error_embed("", Some(start_time))
281+
.description("**No Permission:** You need to be verified to see the join information's")
282+
)
283+
.ephemeral(true)
284+
)
285+
).await?;
286+
return Ok(());
287+
}
288+
289+
let mut response = create_base_embed(Some(start_time))
290+
.title("Join Information's")
291+
.description(
292+
format!(
293+
"-# {}:{}\n- **Cracked:** {}\n- **Whitelist:** {}",
294+
server_info.server_ip,
295+
server_info.server_port,
296+
server_history.cracked.map(|b| if b { "Yes" } else { "No" }).unwrap_or("Unknown"),
297+
server_history.whitelist.map(|b| if b { "Enabled" } else { "Disabled" }).unwrap_or("Unknown")
298+
)
299+
);
300+
301+
if let Some(kick_msg) = &server_history.kick_message {
302+
response = response.field("Kick Message", format!("```{}```", kick_msg), true);
303+
}
304+
305+
interaction.create_response(
306+
&ctx.http(),
307+
CreateInteractionResponse::Message(
308+
CreateInteractionResponseMessage::new()
309+
.embed(response)
310+
.ephemeral(true)
311+
)
312+
).await?;
313+
}
314+
259315
"view_plugins" => {
260316
view_plugins(
261317
ctx,

src/discord/actions/server_filter.rs

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use std::time::Duration;
22
use chrono::{DateTime, Utc};
33
use futures::StreamExt;
44
use poise::{CreateReply, ReplyHandle};
5-
use serenity::all::{ButtonStyle, ComponentInteractionCollector, ComponentInteractionDataKind, CreateActionRow, CreateButton, CreateEmbed, CreateInteractionResponse, CreateInteractionResponseMessage, CreateSelectMenu, CreateSelectMenuKind, CreateSelectMenuOption, EditInteractionResponse, EditMessage, Message};
5+
use serenity::all::{ButtonStyle, ComponentInteractionCollector, ComponentInteractionDataKind, CreateActionRow, CreateButton, CreateEmbed, CreateInteractionResponse, CreateInteractionResponseMessage, CreateSelectMenu, CreateSelectMenuKind, CreateSelectMenuOption, EditInteractionResponse, EditMessage, Message, RoleId};
66
use serenity::all::CreateInteractionResponse::UpdateMessage;
7+
use crate::config;
78
use crate::database::server::search_servers;
89
use crate::discord::{create_base_embed, create_error_embed, create_loading_embed, create_success_embed, open_string_input_modal, Context, Error};
910
use crate::discord::actions::paginator::create_paged_server_view;
@@ -113,29 +114,32 @@ impl SearchFilters {
113114
pub async fn open_filter_ui(ctx: Context<'_>, reply: ReplyHandle<'_>) -> Result<(), Error> {
114115
let mut filters = SearchFilters::default();
115116

116-
let make_home_action_row = |disabled, filter_is_none|
117-
vec![
118-
CreateActionRow::SelectMenu(CreateSelectMenu::new("server_filter", CreateSelectMenuKind::String {
119-
options: vec![
120-
CreateSelectMenuOption::new("Description", "edit_description").emoji('📝'),
121-
122-
CreateSelectMenuOption::new("Max Players", "edit_max_players").emoji('👥'),
123-
CreateSelectMenuOption::new("Online Players", "edit_online_players").emoji('👥'),
124-
//CreateSelectMenuOption::new("Player Sample", "edit_player_sample").emoji('👥'),
125-
126-
CreateSelectMenuOption::new("Version", "edit_version").emoji('📶'),
127-
CreateSelectMenuOption::new("Enforce Secure Chat", "edit_enforce_secure_chat").emoji('💬'),
117+
let make_home_action_row = |disabled, filter_is_none, has_perm| {
118+
let mut options = vec![
119+
CreateSelectMenuOption::new("Description", "edit_description").emoji('📝'),
120+
CreateSelectMenuOption::new("Max Players", "edit_max_players").emoji('👥'),
121+
CreateSelectMenuOption::new("Online Players", "edit_online_players").emoji('👥'),
122+
//CreateSelectMenuOption::new("Player Sample", "edit_player_sample").emoji('👥'),
123+
CreateSelectMenuOption::new("Version", "edit_version").emoji('📶'),
124+
CreateSelectMenuOption::new("Enforce Secure Chat", "edit_enforce_secure_chat").emoji('💬'),
125+
CreateSelectMenuOption::new("Modded Server", "edit_modding").emoji('🧩'),
126+
CreateSelectMenuOption::new("Plugins", "edit_plugins").emoji('🧩'),
127+
CreateSelectMenuOption::new("Software", "edit_software").emoji('📖'),
128+
];
128129

129-
CreateSelectMenuOption::new("Modded Server", "edit_modding").emoji('🧩'),
130+
if has_perm {
131+
options.extend([
132+
CreateSelectMenuOption::new("Kick Message", "edit_kick_message").emoji('📝'),
133+
CreateSelectMenuOption::new("Cracked", "edit_cracked").emoji('🔓'),
134+
CreateSelectMenuOption::new("Whitelist", "edit_whitelist").emoji('🔓')
135+
]);
136+
}
130137

131-
CreateSelectMenuOption::new("Plugins", "edit_plugins").emoji('🧩'),
132-
CreateSelectMenuOption::new("Software", "edit_software").emoji('📖'),
138+
let select_menu = CreateSelectMenu::new("server_filter", CreateSelectMenuKind::String { options })
139+
.disabled(disabled);
133140

134-
CreateSelectMenuOption::new("Kick Message", "edit_kick_message").emoji('📝'),
135-
CreateSelectMenuOption::new("Cracked", "edit_cracked").emoji('🔓'),
136-
CreateSelectMenuOption::new("Whitelist", "edit_whitelist").emoji('🔓')
137-
]
138-
}).disabled(disabled)),
141+
vec![
142+
CreateActionRow::SelectMenu(select_menu),
139143
CreateActionRow::Buttons(vec![
140144
CreateButton::new("search")
141145
.label("Search")
@@ -148,14 +152,28 @@ pub async fn open_filter_ui(ctx: Context<'_>, reply: ReplyHandle<'_>) -> Result<
148152
.emoji('🗑')
149153
.disabled(disabled || filter_is_none)
150154
])
151-
];
155+
]
156+
};
152157

153158
loop {
154159
let start_time = Utc::now();
155160

161+
let cfg = config::MainConfig::get().ok();
162+
let required_role_id = cfg.and_then(|c| c.discord.join_verify_role).map(RoleId::new);
163+
164+
let has_permission = if let Some(role_id) = required_role_id {
165+
if let Some(guild_id) = ctx.guild_id() {
166+
ctx.author().has_role(ctx.serenity_context(), guild_id, role_id).await.unwrap_or(false)
167+
} else {
168+
false
169+
}
170+
} else {
171+
false
172+
};
173+
156174
reply.edit(ctx, CreateReply::default()
157175
.embed(filters.build_homepage(start_time))
158-
.components(make_home_action_row(false, filters.is_empty()))
176+
.components(make_home_action_row(false, filters.is_empty(), has_permission))
159177
).await?;
160178

161179
let collector = ComponentInteractionCollector::new(ctx.serenity_context())
@@ -253,7 +271,7 @@ pub async fn open_filter_ui(ctx: Context<'_>, reply: ReplyHandle<'_>) -> Result<
253271

254272
reply.edit(ctx, CreateReply::default()
255273
.embed(filters.build_homepage(Utc::now()))
256-
.components(make_home_action_row(true, true))
274+
.components(make_home_action_row(true, true, false))
257275
).await?;
258276
Ok(())
259277
}

0 commit comments

Comments
 (0)