diff --git a/.vscode/settings.json b/.vscode/settings.json index 4d9636b..daba894 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,15 @@ { - "rust-analyzer.showUnlinkedFileNotification": false + "rust-analyzer.showUnlinkedFileNotification": false, + "sqltools.connections": [ + { + "previewLimit": 50, + "server": "postgresql", + "port": 5432, + "askForPassword": true, + "driver": "PostgreSQL", + "name": "hangitbot", + "database": "hangitbot", + "username": "hangitbot" + } + ] } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 7c4e92c..f387171 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2379,9 +2379,9 @@ dependencies = [ [[package]] name = "sea-query" -version = "0.30.2" +version = "0.30.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3e6bba153bb198646c8762c48414942a38db27d142e44735a133cabddcc820" +checksum = "4166a1e072292d46dc91f31617c2a1cdaf55a8be4b5c9f4bf2ba248e3ac4999b" dependencies = [ "bigdecimal", "chrono", diff --git a/src/commands.rs b/src/commands.rs index b4b5b91..285625b 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,16 +1,16 @@ -use std::{collections::HashMap, error::Error}; +use std::collections::HashMap; use rand::{rngs::OsRng, Rng}; use sea_orm::DbErr; use strfmt::Format; use teloxide::{ - payloads::{SendMessage, SendMessageSetters}, + payloads::SendMessageSetters, prelude::Bot, - requests::{JsonRequest, Requester}, + requests::Requester, types::{Message, ParseMode}, - utils::{command::BotCommands, markdown::escape}, + utils::command::BotCommands, + RequestError, }; -use wd_log::log_error_ln; use crate::{ config::Args, @@ -65,43 +65,42 @@ impl CommandHandler { bot: &Bot, message: &Message, text: String, - ) -> JsonRequest { + ) -> Result { bot.send_message(message.chat.id, text) .reply_to_message_id(message.id) .parse_mode(ParseMode::MarkdownV2) + .await } pub async fn help_handler( &self, bot: &Bot, message: &Message, - ) -> Result, Box> { - Ok(self - .send_text_reply(bot, message, Commands::descriptions().to_string()) - .await) + ) -> Result { + self.send_text_reply(bot, message, Commands::descriptions().to_string()) + .await } pub async fn about_handler( &self, bot: &Bot, message: &Message, - ) -> Result, Box> { - Ok(self - .send_text_reply(bot, message, BOT_ABOUT.to_string()) - .await) + ) -> Result { + self.send_text_reply(bot, message, BOT_ABOUT.to_string()) + .await } pub async fn hangit_handler( &self, bot: &Bot, message: &Message, - ) -> Result, Box> { + ) -> Result { let reply = match message.reply_to_message() { Some(reply) => reply, None => { - return Ok(self + return self .send_text_reply(bot, message, BOT_TEXT_NO_TARGET.to_string()) - .await) + .await } }; @@ -113,7 +112,7 @@ impl CommandHandler { }; let mut vars = HashMap::new(); - + let index = if is_self { OsRng.gen::() % BOT_TEXT_HANGED_SELF.len() } else { @@ -132,56 +131,46 @@ impl CommandHandler { .controller .hangit(&user.full_name(), message.chat.id) .await; - Ok(self - .send_text_reply(bot, reply, escape(&text.format(&vars).unwrap())) - .await) + self.send_text_reply(bot, reply, text.format(&vars).unwrap()) + .await + } + None => { + self.send_text_reply(bot, message, BOT_TEXT_IS_CHANNEL.to_string()) + .await } - None => Ok(self - .send_text_reply(bot, message, BOT_TEXT_IS_CHANNEL.to_string()) - .await), } } - pub async fn top_handler( - &self, - bot: &Bot, - message: &Message, - ) -> Result, Box> { - let chat_id = message.chat.id; - let scope = match chat_id.is_group() { + pub async fn top_handler(&self, bot: &Bot, message: &Message) -> Result { + let chat = &message.chat; + let scope = match chat.is_group() || chat.is_supergroup() { true => BOT_TEXT_TOP_GROUP, false => BOT_TEXT_TOP_GLOBAL, }; let mut index = 1; - let mut text = format!("{}-{}\n\n", BOT_TEXT_TOP_TITLE, scope); - let results = match self.controller.top(chat_id).await { - Ok(r) => match r { - Some(result) => result, - None => { - return Ok(self - .send_text_reply(bot, message, BOT_TEXT_TOP_NONE.to_string()) - .await) - } - }, - Err(error) => { - log_error_ln!("{}", error); - return Err(Box::new(error)); + let mut text = format!("{}\\-{}\n\n", BOT_TEXT_TOP_TITLE, scope); + let results = match self.controller.top(chat).await { + Some(result) => result, + None => { + return self + .send_text_reply(bot, message, BOT_TEXT_TOP_NONE.to_string()) + .await } }; for result in results { - let mut vars = HashMap::new(); + let mut vars: HashMap = HashMap::new(); vars.insert("name".to_string(), result.name); vars.insert("count".to_string(), result.counts.to_string()); let record = BOT_TEXT_TOP_TEMPLATE.format(&vars).unwrap(); - text = format!("{}{} {}\n", text, index, record); + text = format!("{}{}\\. {}\n", text, index, record); index += 1; } - Ok(self.send_text_reply(bot, message, text).await) + self.send_text_reply(bot, message, text).await } } diff --git a/src/db_controller.rs b/src/db_controller.rs index 95a24ff..93225a3 100644 --- a/src/db_controller.rs +++ b/src/db_controller.rs @@ -1,11 +1,19 @@ use migration::{Migrator, MigratorTrait}; use models::prelude::*; use sea_orm::{ - ActiveModelTrait, ColumnTrait, Database, DatabaseConnection, DbErr, EntityTrait, - PaginatorTrait, QueryFilter, QueryOrder, Set, TransactionTrait, + ActiveModelTrait, ColumnTrait, ConnectionTrait, Database, DatabaseConnection, + DbErr, EntityTrait, QueryFilter, QueryOrder, QuerySelect, QueryTrait, Set, TransactionTrait, FromQueryResult, prelude::BigDecimal, }; -use teloxide::types::ChatId; -use wd_log::{log_info_ln, log_warn_ln}; +use teloxide::types::{Chat, ChatId}; +use wd_log::{log_debug_ln, log_error_ln, log_info_ln, log_warn_ln}; + + +#[derive(Debug, FromQueryResult)] +pub struct TopData { + pub name: String, + pub counts: BigDecimal, +} + #[derive(Debug, Clone)] pub struct Controller { @@ -63,28 +71,49 @@ impl Controller { } /// stats - pub async fn top(&self, group_id: ChatId) -> Result>, DbErr> { + pub async fn top(&self, chat: &Chat) -> Option> { const LIMIT: u64 = 10; - let transcation = self.db.begin().await?; - - let query = match group_id.is_group() { - true => { - Stats::find() - .filter(StatsColumn::GroupId.eq(group_id.0)) - .order_by_desc(StatsColumn::Counts) - .paginate(&transcation, LIMIT) - .fetch() - .await? - } - false => { - Stats::find() - .order_by_desc(StatsColumn::Counts) - .paginate(&transcation, LIMIT) - .fetch() - .await? + let transcation = match self.db.begin().await { + Ok(t) => t, + Err(error) => { + log_error_ln!("{}", error); + return None; } }; - Ok(Some(query)) + let query = match chat.is_group() || chat.is_supergroup() { + true => { + Stats::find() + .filter(StatsColumn::GroupId.eq(chat.id.0)) + .order_by_desc(StatsColumn::Counts) + .limit(LIMIT).into_model() + .all(&transcation) + .await + } + false => { + let query = Stats::find() + .select_only() + .column(StatsColumn::Name) + .column_as(StatsColumn::Counts.sum(), "counts") + .group_by(StatsColumn::Name) + .order_by_desc(StatsColumn::Counts.sum()) + .limit(LIMIT); + + log_debug_ln!( + "SQL: {:?}", + query.build(transcation.get_database_backend()).to_string() + ); + + query.into_model().all(&transcation).await + } + }; + + match query { + Ok(query) => Some(query), + Err(error) => { + log_error_ln!("{}", error); + None + } + } } } diff --git a/src/main.rs b/src/main.rs index 729f3b2..ee987f6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,14 +43,25 @@ async fn main() { Commands::repl(bot, move |bot: Bot, message: Message, cmd: Commands| { let command_handler = command_handler.clone(); + async move { - let _ = match cmd { - Commands::Help => command_handler.clone().help_handler(&bot, &message).await, - Commands::About => command_handler.clone().about_handler(&bot, &message).await, - Commands::Top => command_handler.clone().top_handler(&bot, &message).await, - Commands::HangIt => command_handler.clone().hangit_handler(&bot, &message).await, + let r = match cmd { + Commands::Help => command_handler.help_handler(&bot, &message).await, + Commands::About => command_handler.about_handler(&bot, &message).await, + Commands::Top => command_handler.top_handler(&bot, &message).await, + Commands::HangIt => command_handler.hangit_handler(&bot, &message).await, }; - Ok(()) + + match r { + Ok(_r) => { + log_debug_ln!("will send: {:?}", _r.text()); + Ok(()) + }, + Err(err) => { + log_error_ln!("{:?}", err); + Err(err) + } + } } }) .await; diff --git a/src/messages.rs b/src/messages.rs index e1118c0..f5a5f17 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -1,5 +1,5 @@ pub const BOT_ABOUT: &'static str = - "*Hang it bot*\n\nHang your boss up!\n[Github](https://github.com/senseab/saysthbot-reborn) @ssthbot"; + "*Hang it bot*\n\nHang your boss up\\!\n[Github](https://github.com/senseab/hangitbot) @hangitbot"; pub const BOT_TEXT_NO_TARGET: &'static str = "请在回复某一条信息时使用该指令"; pub const BOT_TEXT_IS_CHANNEL: &'static str = "这不是个人,吊不起来";