Skip to content

Commit 32eb7f1

Browse files
authored
Merge pull request #13 from f-code-club/fix/correct-moderator-check
Fix/correct moderator check
2 parents f35f6f0 + a685ec7 commit 32eb7f1

11 files changed

Lines changed: 83 additions & 14 deletions

File tree

.github/workflows/deploy.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ jobs:
4848
REGISTRY: ghcr.io/${{ github.repository }}
4949
BOT_PREFIX: ${{ secrets.BOT_PREFIX }}
5050
BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
51+
CANDIDATE_ROLE: ${{ secrets.CANDIDATE_ROLE }}
52+
MODERATOR_ROLE: ${{ secrets.MODERATOR_ROLE }}
5153
steps:
5254
- name: Checkout Develop
5355
uses: actions/checkout@v3

compose.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ services:
88
DATABASE_URL: "sqlite:database/data.db?mode=rwc"
99
BOT_PREFIX: ${BOT_PREFIX}
1010
BOT_TOKEN: ${BOT_TOKEN}
11+
CANDIDATE_ROLE: ${CANDIDATE_ROLE}
12+
MODERATOR_ROLE: ${MODERATOR_ROLE}
1113
restart: always
1214

1315
volumes:

src/check/is_moderator.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use anyhow::{Result, anyhow};
2+
use poise::CreateReply;
3+
4+
use crate::{Context, Message};
5+
6+
#[tracing::instrument]
7+
pub async fn is_moderator(ctx: Context<'_>) -> Result<bool> {
8+
let config = &ctx.data().config;
9+
10+
let Some(guild) = ctx.guild_id() else {
11+
return Err(anyhow!("Must be in a guild"));
12+
};
13+
let roles = guild.roles(ctx.http()).await?;
14+
let role_id = roles.iter().find_map(|(id, role)| {
15+
if role.name == config.moderator_role {
16+
Some(id)
17+
} else {
18+
None
19+
}
20+
});
21+
let Some(role_id) = role_id else {
22+
return Err(anyhow!("No role with given name"));
23+
};
24+
25+
if ctx.author().has_role(ctx.http(), guild, role_id).await? {
26+
return Ok(true);
27+
}
28+
29+
ctx.send(
30+
CreateReply::default()
31+
.ephemeral(true)
32+
.reply(true)
33+
.content(Message::Unauthorized),
34+
)
35+
.await?;
36+
37+
Ok(false)
38+
}

src/check/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
mod is_moderator;
2+
3+
pub use is_moderator::is_moderator;

src/command/add.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use anyhow::Result;
22
use poise::serenity_prelude as serenity;
33

4-
use crate::{Context, Message, database, util};
4+
use crate::{Context, Message, check, database, util};
55

66
/// Add one or more candidate IDs to the candidates database from a text file.
77
#[tracing::instrument]
88
#[poise::command(
99
slash_command,
1010
prefix_command,
1111
ephemeral,
12-
required_permissions = "MANAGE_MESSAGES | MANAGE_THREADS"
12+
check = "check::is_moderator"
1313
)]
1414
pub async fn add(
1515
ctx: Context<'_>,

src/command/delete.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use anyhow::Result;
22

3-
use crate::{Context, Message, database, util};
3+
use crate::{Context, Message, check, database, util};
44

55
/// Delete a candidate by ID from the candidates database.
66
#[tracing::instrument]
77
#[poise::command(
88
slash_command,
99
prefix_command,
1010
ephemeral,
11-
required_permissions = "MANAGE_MESSAGES | MANAGE_THREADS"
11+
check = "check::is_moderator"
1212
)]
1313
pub async fn delete(ctx: Context<'_>, id: String) -> Result<()> {
1414
let pool = &ctx.data().pool;

src/command/verify.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@ use poise::serenity_prelude::EditRole;
33

44
use crate::{Context, Message, database, util};
55

6-
const ROLE: &str = "Round 1: Challenger";
7-
86
/// Verify a candidate and assign role upon success.
97
#[tracing::instrument]
108
#[poise::command(slash_command, prefix_command, ephemeral)]
119
pub async fn verify(ctx: Context<'_>, id: String) -> Result<()> {
1210
let pool = &ctx.data().pool;
11+
let config = &ctx.data().config;
1312

1413
if !util::is_valid_id(&id) {
1514
ctx.reply(Message::InvalidId).await?;
@@ -52,7 +51,10 @@ pub async fn verify(ctx: Context<'_>, id: String) -> Result<()> {
5251
return Err(anyhow!("Must be in a guild"));
5352
};
5453
let role = guild
55-
.create_role(ctx.http(), EditRole::new().name(ROLE))
54+
.create_role(
55+
ctx.http(),
56+
EditRole::new().name(config.candidate_role.clone()),
57+
)
5658
.await?;
5759
member.add_role(ctx.http(), role.id).await?;
5860

src/config.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@ fn default_bot_prefix() -> String {
99
"!".to_string()
1010
}
1111

12-
#[derive(Debug, Deserialize)]
12+
fn default_candidate_role() -> String {
13+
"Round 1: Challenger".to_string()
14+
}
15+
16+
fn default_moderator_role() -> String {
17+
"Moderator".to_string()
18+
}
19+
20+
#[derive(Debug, Deserialize, Clone)]
1321
pub struct Config {
1422
#[serde(default = "default_database_url")]
1523
pub database_url: String,
@@ -18,6 +26,12 @@ pub struct Config {
1826
pub bot_prefix: String,
1927

2028
pub bot_token: String,
29+
30+
#[serde(default = "default_candidate_role")]
31+
pub candidate_role: String,
32+
33+
#[serde(default = "default_moderator_role")]
34+
pub moderator_role: String,
2135
}
2236

2337
impl Config {

src/main.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pub mod check;
12
pub mod command;
23
pub mod config;
34
pub mod database;
@@ -19,6 +20,8 @@ pub type Context<'a> = poise::Context<'a, State, anyhow::Error>;
1920

2021
pub async fn build_bot() -> anyhow::Result<()> {
2122
let config = Config::new()?;
23+
let prefix = config.bot_prefix.clone();
24+
let token = config.bot_token.clone();
2225

2326
let options = FrameworkOptions {
2427
commands: vec![
@@ -29,7 +32,7 @@ pub async fn build_bot() -> anyhow::Result<()> {
2932
command::verify(),
3033
],
3134
prefix_options: poise::PrefixFrameworkOptions {
32-
prefix: Some(config.bot_prefix),
35+
prefix: Some(prefix),
3336
edit_tracker: Some(Arc::new(poise::EditTracker::for_timespan(
3437
Duration::from_secs(3600),
3538
))),
@@ -43,15 +46,15 @@ pub async fn build_bot() -> anyhow::Result<()> {
4346
Box::pin(async move {
4447
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
4548

46-
State::new(&config.database_url).await
49+
State::new(config).await
4750
})
4851
})
4952
.options(options)
5053
.build();
5154

5255
let intents = GatewayIntents::all() | GatewayIntents::GUILD_MESSAGE_REACTIONS;
5356

54-
let mut client = Client::builder(&config.bot_token, intents)
57+
let mut client = Client::builder(&token, intents)
5558
.framework(framework)
5659
.await?;
5760

src/message.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub enum Message<'a> {
1010
NotRegistered,
1111
InvalidName,
1212
Verified(Option<NaiveDateTime>),
13+
Unauthorized,
1314
Error,
1415
}
1516

@@ -23,6 +24,7 @@ impl From<Message<'_>> for String {
2324
Message::Verified(None) => "Bạn đã verify thành công".to_string(),
2425
Message::Verified(Some(time)) => format!("Bạn đã verify thành công vào {}.", util::format_datetime(time)),
2526
Message::InvalidName => "Vui lòng đặt tên đúng quy tắc.".to_string(),
27+
Message::Unauthorized => "Lệnh dành riêng cho moderator".to_string(),
2628
Message::Error => "Có một số lỗi đã xảy ra bạn thử lại trong ít phút hoặc tạo ticket để được hỗ trợ nhé!".to_string(),
2729
}
2830
}

0 commit comments

Comments
 (0)