Skip to content

Commit

Permalink
Merge pull request #1 from SharliBeicon/feature/admin-commands
Browse files Browse the repository at this point in the history
Feature/admin commands | unit testing
  • Loading branch information
SharliBeicon authored Jun 14, 2024
2 parents f7cfcbb + eae9d49 commit deb5707
Show file tree
Hide file tree
Showing 10 changed files with 410 additions and 106 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ jobs:
- uses: actions/checkout@v3
- name: Build
run: cargo build --verbose
#- name: Run tests
# run: cargo test --verbose
- name: Run tests
run: cargo test --verbose
59 changes: 56 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "telitairos-bot"
description = "A fully funcional AI Powered assistant Telegram Bot"
version = "0.1.2"
version = "0.2.0"
edition = "2021"
license = "MIT"
keywords = ["ai", "telegram", "bot", "admin", "chatbot"]
Expand All @@ -10,9 +10,9 @@ exclude = ["src/main.rs"]

[dependencies]
async-openai = "0.23.2"

teloxide = { version = "0.12", features = ["macros"] }
log = "0.4"
pretty_env_logger = "0.4"
tokio = { version = "1.38", features = ["rt-multi-thread", "macros"] }
string-builder = "0.2.0"
chrono = "0.4.38"
7 changes: 6 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ tokio = { version = "1.8", features = ["rt-multi-thread", "macros"] }
```

## Supported commands
You can either:
You can do either:

### 👮🚨 ADMIN Commands
- `/mute X {h/m/s/p}` -> Mute an User from the Chat Group the selected time. 'p' is for 'permanent'
- `/ban X {h/m/s/p}` -> Ban an User from the Chat Group the selected time. 'p' is for 'permanent'
### 🦀 AI Commands
- `/ask` for a specified question.
- `/mediate` to read the last N messages of a chat group and mitigate an argument.

Expand Down
76 changes: 0 additions & 76 deletions src/bot.rs

This file was deleted.

152 changes: 152 additions & 0 deletions src/bot/admin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use crate::bot::*;
use chrono::Duration;
use teloxide::{
payloads::RestrictChatMemberSetters,
types::{ChatPermissions, ParseMode},
};

#[derive(BotCommands, Clone, PartialEq)]
#[command(
rename_rule = "lowercase",
description = "Supported ADMIN Commands",
parse_with = "split"
)]
pub enum AdminCommand {
#[command(description = "Display this text\\.")]
Help,

#[command(
description = "`/mute X {h/m/s/p}` \\-\\> Mute an User from the Chat Group the selected time\\. 'p' is for 'permanent'"
)]
Mute(types::TimeAmount, types::UnitOfTime),

#[command(
description = "`/ban X {h/m/s/p}` \\-\\> Ban an User from the Chat Group the selected time\\. 'p' is for 'permanent'"
)]
Ban(types::TimeAmount, types::UnitOfTime),
}

pub async fn handle_admin_commands(
bot: Bot,
msg: Message,
cmd: AdminCommand,
) -> ResponseResult<()> {
match cmd {
AdminCommand::Help => {
bot.send_message(msg.chat.id, all_command_descriptions())
.parse_mode(ParseMode::MarkdownV2)
.await?;
}
AdminCommand::Mute(time_amount, unit_of_time) => {
mute_user(bot, msg, calc_time(time_amount, unit_of_time)).await?;
}
AdminCommand::Ban(time_amount, unit_of_time) => {
ban_user(bot, msg, calc_time(time_amount, unit_of_time)).await?;
}
};

Ok(())
}

async fn mute_user(bot: Bot, msg: Message, time: Option<Duration>) -> ResponseResult<()> {
let duration = match time {
Some(d) => d,
None => {
bot.send_message(msg.chat.id, "Send a properly formatted time span")
.await?;
return Ok(());
}
};

match msg.reply_to_message() {
Some(replied) => {
bot.restrict_chat_member(
msg.chat.id,
replied.from().expect("Must be MessageKind::Common").id,
ChatPermissions::empty(),
)
.until_date(msg.date + duration)
.await?;
}
None => {
bot.send_message(
msg.chat.id,
"Use this command in a reply to another message!",
)
.await?;
}
}

Ok(())
}

async fn ban_user(bot: Bot, msg: Message, time: Option<Duration>) -> ResponseResult<()> {
let duration = match time {
Some(d) => d,
None => {
bot.send_message(msg.chat.id, "Send a properly formatted time span")
.await?;
return Ok(());
}
};

match msg.reply_to_message() {
Some(replied) => {
bot.kick_chat_member(
msg.chat.id,
replied.from().expect("Must be MessageKind::Common").id,
)
.until_date(msg.date + duration)
.await?;
}
None => {
bot.send_message(
msg.chat.id,
"Use this command in a reply to another message!",
)
.await?;
}
}

Ok(())
}

fn calc_time(time_amount: types::TimeAmount, unit_of_time: types::UnitOfTime) -> Option<Duration> {
match unit_of_time {
types::UnitOfTime::Seconds => Duration::try_seconds(time_amount.into()),
types::UnitOfTime::Minutes => Duration::try_minutes(time_amount.into()),
types::UnitOfTime::Hours => Duration::try_hours(time_amount.into()),
types::UnitOfTime::Permanent => Some(Duration::max_value()),
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::types::*;
use chrono::Duration;

#[test]
fn calc_time_seconds() {
let result = calc_time(10, UnitOfTime::Seconds);
assert_eq!(result, Some(Duration::seconds(10)));
}

#[test]
fn calc_time_minutes() {
let result = calc_time(10, UnitOfTime::Minutes);
assert_eq!(result, Some(Duration::seconds(600)));
}

#[test]
fn calc_time_hours() {
let result = calc_time(2, UnitOfTime::Hours);
assert_eq!(result, Some(Duration::seconds(7200)));
}

#[test]
fn calc_time_permanent() {
let result = calc_time(0, UnitOfTime::Permanent);
assert_eq!(result, Some(Duration::max_value()));
}
}
Loading

0 comments on commit deb5707

Please sign in to comment.