From 594002a42e747f2c07798daa6fc4ca1540a3ee55 Mon Sep 17 00:00:00 2001 From: mykola2312 <49044616+mykola2312@users.noreply.github.com> Date: Sun, 3 Mar 2024 23:40:30 +0200 Subject: [PATCH] implement approve and decline commands --- locales/en.yml | 8 ++- src/bot.rs | 2 +- src/bot/bot.rs | 16 +++--- src/bot/request.rs | 128 +++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 140 insertions(+), 14 deletions(-) diff --git a/locales/en.yml b/locales/en.yml index 68ebede..87ec89c 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -11,4 +11,10 @@ already_has_requested: "Stop spamming requests. That ain't gonna grant ya the do request_added: "Your requested has been added. Admins have been notifed. You should DM bot with /start to enable personal notifications" admin_notify_request: "User %{user} awaits request approval" not_an_admin: "You are not an admin. Back off" -request_list_header: "Current user requests for downloading:\n" \ No newline at end of file +request_list_header: "Current user requests for downloading:\n" +not_valid_integer: "This is not a valid integer." +request_not_found: "Request not found" +request_approved: "Request has been approved. The user should now be able to download" +your_request_approved: "Congrats! Your request has been approved. Now you should be able to download" +request_declined: "Request has been declined (deleted)." +your_request_declined: "huge L for ya - ur request was deleted and fuck you" \ No newline at end of file diff --git a/src/bot.rs b/src/bot.rs index 6b8c04d..30a011a 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -17,7 +17,7 @@ macro_rules! reply_i18n_and_return { #[macro_export] macro_rules! parse_integer { - ($bot:expr, $chat_id:expr, $integer:expr, $out:expr) => {{ + ($bot:expr, $chat_id:expr, $integer:expr) => {{ let out: i64 = match $integer.parse() { Ok(integer) => integer, Err(_) => { diff --git a/src/bot/bot.rs b/src/bot/bot.rs index 8be90ce..f2d50f1 100644 --- a/src/bot/bot.rs +++ b/src/bot/bot.rs @@ -12,12 +12,11 @@ use tracing::{event, Level}; use super::start::handle_new_chat_member; use super::types::*; -use crate::bot::notify::notify_admins; use crate::db::DbPool; use super::dl::cmd_download; use super::op::cmd_op; -use super::request::{cmd_listrequests, cmd_request}; +use super::request::{cmd_listrequests, cmd_request, cmd_approve, cmd_decline}; use super::start::{cmd_start, handle_my_chat_member}; fn parse_env(name: &str) -> T @@ -65,7 +64,9 @@ fn schema() -> UpdateHandler { .branch(case![Command::Download(url)].endpoint(cmd_download)) .branch(case![Command::OP].endpoint(cmd_op)) .branch(case![Command::Request(text)].endpoint(cmd_request)) - .branch(case![Command::ListRequests].endpoint(cmd_listrequests)); + .branch(case![Command::ListRequests].endpoint(cmd_listrequests)) + .branch(case![Command::Approve(text)].endpoint(cmd_approve)) + .branch(case![Command::Decline(text)].endpoint(cmd_decline)); let message_handler = Update::filter_message().branch(command_handler); let raw_message_handler = Update::filter_message().branch(dptree::endpoint(handle_message)); @@ -109,21 +110,20 @@ async fn handle_message( #[command(rename_rule = "lowercase")] enum Command { Test, - #[command(alias = "start")] Start, - #[command(alias = "dl")] Download(String), - #[command(alias = "op")] OP, - #[command(alias = "request")] Request(String), - #[command(alias = "listrequests")] ListRequests, + #[command(alias = "approve")] + Approve(String), + #[command(alias = "decline")] + Decline(String), } async fn cmd_test(bot: Bot, msg: Message, _db: DbPool) -> HandlerResult { diff --git a/src/bot/request.rs b/src/bot/request.rs index 78b1c1d..387af91 100644 --- a/src/bot/request.rs +++ b/src/bot/request.rs @@ -1,14 +1,14 @@ use rust_i18n::t; use sqlx::Row; -use teloxide::{prelude::*, requests}; +use teloxide::types::Recipient; +use teloxide::prelude::*; use tracing::{event, Level}; use super::notify::notify_admins; use super::types::HandlerResult; -use crate::db::chat::find_or_create_chat; use crate::db::user::find_or_create_user; use crate::db::{DbPool, User}; -use crate::reply_i18n_and_return; +use crate::{parse_integer, reply_i18n_and_return}; pub async fn cmd_request(bot: Bot, msg: Message, text: String, db: DbPool) -> HandlerResult { if text.len() < 16 { @@ -78,7 +78,7 @@ pub async fn cmd_listrequests(bot: Bot, msg: Message, db: DbPool) -> HandlerResu ) .fetch_all(&db) .await?; - + let mut list = String::new(); list.push_str(t!("request_list_header").to_string().as_str()); for request in requests { @@ -93,3 +93,123 @@ pub async fn cmd_listrequests(bot: Bot, msg: Message, db: DbPool) -> HandlerResu Ok(()) } + +pub async fn cmd_approve(bot: Bot, msg: Message, id: String, db: DbPool) -> HandlerResult { + let id: i64 = parse_integer!(bot, msg.chat.id, id); + + if let Some(user) = msg.from() { + let user = find_or_create_user(&db, user).await?; + if user.is_admin != 1 { + reply_i18n_and_return!(bot, msg.chat.id, "not_an_admin"); + } + + // get request + let res: Result = sqlx::query_as( + "SELECT request.id AS request_id, request.message, user.* + FROM request + INNER JOIN user ON request.requested_by = user.id + WHERE request_id = $1 AND request.is_approved = 0 + LIMIT 1;", + ) + .bind(id) + .fetch_one(&db) + .await; + let request = match res { + Ok(request) => request, + Err(e) => match e { + sqlx::Error::RowNotFound => { + bot.send_message(msg.chat.id, t!("request_not_found")) + .await?; + return Ok(()); + } + _ => return Err(Box::new(e)), + }, + }; + + // approve request + sqlx::query("UPDATE request SET approved_by = $1, is_approved = 1 WHERE id = $2;") + .bind(user.id) + .bind(request.request_id) + .execute(&db) + .await?; + event!( + Level::INFO, + "approved request {} by {} for {}", + request.request_id, + user, + request.user + ); + bot.send_message(msg.chat.id, t!("request_approved")) + .await?; + + // notify target user + if request.user.has_private_chat == 1 { + bot.send_message( + Recipient::Id(ChatId(request.user.tg_id)), + t!("your_request_approved"), + ) + .await?; + } + } + + Ok(()) +} + +pub async fn cmd_decline(bot: Bot, msg: Message, id: String, db: DbPool) -> HandlerResult { + let id: i64 = parse_integer!(bot, msg.chat.id, id); + + if let Some(user) = msg.from() { + let user = find_or_create_user(&db, user).await?; + if user.is_admin != 1 { + reply_i18n_and_return!(bot, msg.chat.id, "not_an_admin"); + } + + // get request + let res: Result = sqlx::query_as( + "SELECT request.id AS request_id, request.message, user.* + FROM request + INNER JOIN user ON request.requested_by = user.id + WHERE request_id = $1 AND request.is_approved = 0 + LIMIT 1;", + ) + .bind(id) + .fetch_one(&db) + .await; + let request = match res { + Ok(request) => request, + Err(e) => match e { + sqlx::Error::RowNotFound => { + bot.send_message(msg.chat.id, t!("request_not_found")) + .await?; + return Ok(()); + } + _ => return Err(Box::new(e)), + }, + }; + + // decline request + sqlx::query("DELETE FROM request WHERE id = $1;") + .bind(request.request_id) + .execute(&db).await?; + event!( + Level::INFO, + "declined request {} by {} for {}", + request.request_id, + user, + request.user + ); + bot.send_message(msg.chat.id, t!("request_declined")) + .await?; + + // notify target user + if request.user.has_private_chat == 1 { + bot.send_message( + Recipient::Id(ChatId(request.user.tg_id)), + t!("your_request_declined"), + ) + .await?; + } + } + + Ok(()) +} \ No newline at end of file