mirror of
https://github.com/house-of-vanity/desubot.git
synced 2025-08-21 15:27:14 +00:00
Add /code feature.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "desubot"
|
name = "desubot"
|
||||||
version = "0.1.0"
|
version = "0.5.0"
|
||||||
authors = ["AB <ab@hexor.ru>"]
|
authors = ["AB <ab@hexor.ru>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@@ -32,4 +32,9 @@ markov = "1.1.0"
|
|||||||
rand = "0.7.3"
|
rand = "0.7.3"
|
||||||
mystem = "0.2.1"
|
mystem = "0.2.1"
|
||||||
async-trait = "0.1.42"
|
async-trait = "0.1.42"
|
||||||
sqlparser = "0.7.0"
|
sqlparser = "0.7.0"
|
||||||
|
|
||||||
|
[dependencies.syntect]
|
||||||
|
version = "4.4"
|
||||||
|
default-features = false
|
||||||
|
features = ["parsing", "dump-load", "regex-onig"]
|
2
README
2
README
@@ -9,7 +9,7 @@ Telegram bot with light group statistic and heavy spy features.
|
|||||||
* Generate sentences using Markov Chains trained on history with /markov_all.
|
* Generate sentences using Markov Chains trained on history with /markov_all.
|
||||||
|
|
||||||
== TODO ==
|
== TODO ==
|
||||||
* Syntax highlighting for code exported to image.
|
* Syntax highlighting for CODE exported to image.
|
||||||
|
|
||||||
== Important ==
|
== Important ==
|
||||||
* Desubot uses MyStem by Yandex for word stemming and assume that mystem binary is available in PATH.
|
* Desubot uses MyStem by Yandex for word stemming and assume that mystem binary is available in PATH.
|
||||||
|
36
assets/help_text.rs
Normal file
36
assets/help_text.rs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
static CODE: &str = "<b>Code highlighter</b>
|
||||||
|
|
||||||
|
<i>Usage</i>
|
||||||
|
<pre>/CODE
|
||||||
|
#<theme - Dracula by default>
|
||||||
|
<CODE>
|
||||||
|
#<lang - JS by default></pre>
|
||||||
|
|
||||||
|
Language may be defined by both name and extension - Rust, rs...
|
||||||
|
Max lines - 80
|
||||||
|
|
||||||
|
List of themes:
|
||||||
|
1337
|
||||||
|
DarkNeon
|
||||||
|
Dracula
|
||||||
|
GitHub
|
||||||
|
Monokai_Extended
|
||||||
|
Monokai_Extended_Bright
|
||||||
|
Monokai_Extended_Light
|
||||||
|
Monokai_Extended_Origin
|
||||||
|
Nord
|
||||||
|
OneHalfDark
|
||||||
|
OneHalfLight
|
||||||
|
Solarized_(dark)
|
||||||
|
Solarized_(light)
|
||||||
|
Sublime_Snazzy
|
||||||
|
TwoDark
|
||||||
|
ansi-dark
|
||||||
|
ansi-light
|
||||||
|
base16
|
||||||
|
base16-256
|
||||||
|
gruvbox
|
||||||
|
gruvbox-light
|
||||||
|
gruvbox-white
|
||||||
|
zenburn
|
||||||
|
";
|
1210
src/commands.rs
1210
src/commands.rs
File diff suppressed because it is too large
Load Diff
@@ -348,10 +348,9 @@ pub(crate) async fn get_file(file_id: String) -> Result<i64, errors::Error> {
|
|||||||
file_rowid
|
file_rowid
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_word(word: &String) -> Result<i64, errors::Error> {
|
async fn add_word(word: &str) -> Result<i64, errors::Error> {
|
||||||
match get_stop_word(&word).await {
|
if get_stop_word(&word).await.is_err() {
|
||||||
Err(_) => return Err(errors::Error::WordInStopList),
|
return Err(errors::Error::WordInStopList);
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
let conn = open()?;
|
let conn = open()?;
|
||||||
let word_rowid =
|
let word_rowid =
|
||||||
@@ -365,7 +364,7 @@ async fn add_word(word: &String) -> Result<i64, errors::Error> {
|
|||||||
Ok(word_rowid)
|
Ok(word_rowid)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_stop_word(stop_word: &String) -> Result<(), errors::Error> {
|
async fn get_stop_word(stop_word: &str) -> Result<(), errors::Error> {
|
||||||
let conn = open()?;
|
let conn = open()?;
|
||||||
match conn.execute_named(
|
match conn.execute_named(
|
||||||
"SELECT rowid FROM stop_words WHERE word = (:stop_word)",
|
"SELECT rowid FROM stop_words WHERE word = (:stop_word)",
|
||||||
|
@@ -23,11 +23,39 @@ pub enum Error {
|
|||||||
SQLBannedCommand(String),
|
SQLBannedCommand(String),
|
||||||
SQLInvalidCommand,
|
SQLInvalidCommand,
|
||||||
SQLResultTooLong(String),
|
SQLResultTooLong(String),
|
||||||
|
CodeHighlightningError,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "An error occurred.")
|
write!(f, "An error occurred.")
|
||||||
|
// match self {
|
||||||
|
// _ => write!(f, "An error occurred."),
|
||||||
|
// // Error::UserNotFound => {}
|
||||||
|
// // Error::SQLITE3Error(_) => {}
|
||||||
|
// // Error::TelegramError(_) => {}
|
||||||
|
// // Error::ReqwestError(_) => {}
|
||||||
|
// // Error::ConfNotFound => {}
|
||||||
|
// // Error::WordNotFound => {}
|
||||||
|
// // Error::WordInStopList => {}
|
||||||
|
// // Error::IOError(_) => {}
|
||||||
|
// // Error::FileNotFound => {}
|
||||||
|
// // Error::JsonParseError(_) => {}
|
||||||
|
// // Error::PopenError(_) => {}
|
||||||
|
// // Error::MystemError(_) => {}
|
||||||
|
// // Error::SQLBannedCommand(_) => {}
|
||||||
|
// // Error::SQLInvalidCommand => {}
|
||||||
|
// // Error::SQLResultTooLong(_) => {}
|
||||||
|
// // Error::CodeHighlightningError(Help) => write!(f, "Code highlighter.\
|
||||||
|
// // <b>Usage</b><pre>/CODE\
|
||||||
|
// // #<theme>\
|
||||||
|
// // <CODE>\
|
||||||
|
// // #<lang></pre>\
|
||||||
|
// // \
|
||||||
|
// // List of themes:\
|
||||||
|
// // .")
|
||||||
|
// Error::CodeHighlightningError(help) => write!(f, "{}", help.description)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
386
src/handlers.rs
386
src/handlers.rs
@@ -1,184 +1,202 @@
|
|||||||
//use crate::commands::Command;
|
//use crate::commands::Command;
|
||||||
use crate::commands::{Code, Execute, Here, Markov, MarkovAll, Omedeto, Sql, Top};
|
use crate::commands::{Code, Execute, Here, Markov, MarkovAll, Omedeto, Sql, Top};
|
||||||
use crate::db;
|
use crate::db;
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use mystem::MyStem;
|
use mystem::MyStem;
|
||||||
use telegram_bot::*;
|
use telegram_bot::*;
|
||||||
|
|
||||||
pub async fn handler(
|
|
||||||
api: Api,
|
include!("../assets/help_text.rs");
|
||||||
message: Message,
|
|
||||||
token: String,
|
pub async fn handler(
|
||||||
mystem: &mut MyStem,
|
api: Api,
|
||||||
me: User,
|
message: Message,
|
||||||
) -> Result<(), errors::Error> {
|
token: String,
|
||||||
match message.kind {
|
mystem: &mut MyStem,
|
||||||
MessageKind::Text { ref data, .. } => {
|
me: User,
|
||||||
let title = utils::get_title(&message);
|
) -> Result<(), errors::Error> {
|
||||||
info!(
|
match message.kind {
|
||||||
"<{}({})>[{}({})]: {}",
|
MessageKind::Text { ref data, .. } => {
|
||||||
&message.chat.id(),
|
let title = utils::get_title(&message);
|
||||||
title,
|
info!(
|
||||||
&message.from.id,
|
"<{}({})>[{}({})]: {}",
|
||||||
&message.from.first_name,
|
&message.chat.id(),
|
||||||
data
|
title,
|
||||||
);
|
&message.from.id,
|
||||||
db::add_sentence(&message, mystem).await?;
|
&message.from.first_name,
|
||||||
let cleaned_message = data.replace(&format!("@{}", me.clone().username.unwrap()), "");
|
{if data.len() <= 200 {data} else {&data[..200]}}.replace("\n", " ")
|
||||||
match cleaned_message.as_str() {
|
);
|
||||||
s if s.contains("/here") => {
|
|
||||||
Here {
|
let cleaned_message = data.replace(&format!("@{}", me.clone().username.unwrap()), "");
|
||||||
data: "".to_string(),
|
match cleaned_message.as_str() {
|
||||||
}
|
s if s.to_string().starts_with("/code") => {
|
||||||
.exec(&api, &message)
|
|
||||||
.await?
|
match {
|
||||||
}
|
Code {
|
||||||
s if s.to_string().starts_with("/sql") => match {
|
data: s.replace("/code", ""),
|
||||||
Sql {
|
}
|
||||||
data: s.replace("/sql ", ""),
|
.exec_with_result(&api, &message)
|
||||||
}
|
.await
|
||||||
.exec_with_result(&api, &message)
|
} {
|
||||||
.await
|
Ok(path) => {
|
||||||
} {
|
let file = InputFileUpload::with_path(path.clone());
|
||||||
Ok(msg) => {
|
// api.send(message.chat.document(&file)).await?;
|
||||||
let _ = api
|
//
|
||||||
.send(
|
// // Send an image from disk
|
||||||
message
|
api.send(message.chat.photo(&file)).await?;
|
||||||
.text_reply(msg)
|
//debug!("{:#?}", formatter);
|
||||||
.parse_mode(ParseMode::Html),
|
let _ = std::fs::remove_file(&path);
|
||||||
)
|
}
|
||||||
.await?;
|
Err(_) => {
|
||||||
},
|
let _ = api
|
||||||
Err(e) => {
|
.send(message.text_reply(CODE).parse_mode(ParseMode::Html))
|
||||||
let _ = api
|
.await?;
|
||||||
.send(
|
}
|
||||||
message
|
}
|
||||||
.text_reply(format!("Error: {:#?}", e))
|
}
|
||||||
.parse_mode(ParseMode::Html),
|
s if s.contains("/here") => {
|
||||||
)
|
db::add_sentence(&message, mystem).await?;
|
||||||
.await?;
|
Here {
|
||||||
}
|
data: "".to_string(),
|
||||||
},
|
}
|
||||||
s if s.to_string().starts_with("/code") => {
|
.exec(&api, &message)
|
||||||
Code {
|
.await?
|
||||||
data: s.to_string(),
|
}
|
||||||
}
|
s if s.to_string().starts_with("/sql") => match {
|
||||||
.exec(&api, &message)
|
Sql {
|
||||||
.await?
|
data: s.replace("/sql ", ""),
|
||||||
}
|
}
|
||||||
"/top" => {
|
.exec_with_result(&api, &message)
|
||||||
Top {
|
.await
|
||||||
data: "".to_string(),
|
} {
|
||||||
}
|
Ok(msg) => {
|
||||||
.exec(&api, &message)
|
let _ = api
|
||||||
.await?
|
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
||||||
}
|
.await?;
|
||||||
"/stat" => {
|
}
|
||||||
Top {
|
Err(e) => {
|
||||||
data: "".to_string(),
|
let _ = api
|
||||||
}
|
.send(
|
||||||
.exec(&api, &message)
|
message
|
||||||
.await?
|
.text_reply(format!("Error: {:#?}", e))
|
||||||
}
|
.parse_mode(ParseMode::Html),
|
||||||
"/markov_all" => {
|
)
|
||||||
MarkovAll {
|
.await?;
|
||||||
data: "".to_string(),
|
}
|
||||||
}
|
},
|
||||||
.exec(&api, &message)
|
"/top" => {
|
||||||
.await?
|
Top {
|
||||||
}
|
data: "".to_string(),
|
||||||
"/markov" => {
|
}
|
||||||
Markov {
|
.exec(&api, &message)
|
||||||
data: "".to_string(),
|
.await?
|
||||||
}
|
}
|
||||||
.exec(&api, &message)
|
"/stat" => {
|
||||||
.await?
|
Top {
|
||||||
}
|
data: "".to_string(),
|
||||||
"/omedeto" => {
|
}
|
||||||
Omedeto {
|
.exec(&api, &message)
|
||||||
data: "".to_string(),
|
.await?
|
||||||
}
|
}
|
||||||
.exec_mystem(&api, &message, mystem)
|
"/markov_all" => {
|
||||||
.await?
|
MarkovAll {
|
||||||
}
|
data: "".to_string(),
|
||||||
_ => (),
|
}
|
||||||
}
|
.exec(&api, &message)
|
||||||
}
|
.await?
|
||||||
MessageKind::Photo { ref caption, .. } => {
|
}
|
||||||
let title = utils::get_title(&message);
|
"/markov" => {
|
||||||
info!(
|
Markov {
|
||||||
"<{}({})>[{}({})]: *PHOTO* {}",
|
data: "".to_string(),
|
||||||
&message.chat.id(),
|
}
|
||||||
title,
|
.exec(&api, &message)
|
||||||
&message.from.id,
|
.await?
|
||||||
&message.from.first_name,
|
}
|
||||||
caption.clone().unwrap_or("NO_TITLE".to_string())
|
"/omedeto" => {
|
||||||
);
|
Omedeto {
|
||||||
utils::get_files(api, message, token).await?;
|
data: "".to_string(),
|
||||||
}
|
}
|
||||||
|
.exec_mystem(&api, &message, mystem)
|
||||||
MessageKind::Document { ref caption, .. } => {
|
.await?
|
||||||
let title = utils::get_title(&message);
|
}
|
||||||
info!(
|
_ => db::add_sentence(&message, mystem).await?,
|
||||||
"<{}({})>[{}({})]: *DOCUMENT* {}",
|
}
|
||||||
&message.chat.id(),
|
}
|
||||||
title,
|
MessageKind::Photo { ref caption, .. } => {
|
||||||
&message.from.id,
|
let title = utils::get_title(&message);
|
||||||
&message.from.first_name,
|
info!(
|
||||||
caption.clone().unwrap_or("NO_TITLE".to_string())
|
"<{}({})>[{}({})]: *PHOTO* {}",
|
||||||
);
|
&message.chat.id(),
|
||||||
utils::get_files(api, message, token).await?;
|
title,
|
||||||
}
|
&message.from.id,
|
||||||
|
&message.from.first_name,
|
||||||
MessageKind::Sticker { .. } => {
|
caption.clone().unwrap_or_else(|| "NO_TITLE".to_string())
|
||||||
let title = utils::get_title(&message);
|
);
|
||||||
info!(
|
utils::get_files(api, message, token).await?;
|
||||||
"<{}({})>[{}({})]: *STICKER*",
|
}
|
||||||
&message.chat.id(),
|
|
||||||
title,
|
MessageKind::Document { ref caption, .. } => {
|
||||||
&message.from.id,
|
let title = utils::get_title(&message);
|
||||||
&message.from.first_name,
|
info!(
|
||||||
);
|
"<{}({})>[{}({})]: *DOCUMENT* {}",
|
||||||
utils::get_files(api, message, token).await?;
|
&message.chat.id(),
|
||||||
}
|
title,
|
||||||
|
&message.from.id,
|
||||||
MessageKind::Voice { .. } => {
|
&message.from.first_name,
|
||||||
let title = utils::get_title(&message);
|
caption.clone().unwrap_or_else(|| "NO_TITLE".to_string())
|
||||||
info!(
|
);
|
||||||
"<{}({})>[{}({})]: *VOICE*",
|
utils::get_files(api, message, token).await?;
|
||||||
&message.chat.id(),
|
}
|
||||||
title,
|
|
||||||
&message.from.id,
|
MessageKind::Sticker { .. } => {
|
||||||
&message.from.first_name,
|
let title = utils::get_title(&message);
|
||||||
);
|
info!(
|
||||||
utils::get_files(api, message, token).await?;
|
"<{}({})>[{}({})]: *STICKER*",
|
||||||
}
|
&message.chat.id(),
|
||||||
|
title,
|
||||||
MessageKind::Video { .. } => {
|
&message.from.id,
|
||||||
let title = utils::get_title(&message);
|
&message.from.first_name,
|
||||||
info!(
|
);
|
||||||
"<{}({})>[{}({})]: *VIDEO*",
|
utils::get_files(api, message, token).await?;
|
||||||
&message.chat.id(),
|
}
|
||||||
title,
|
|
||||||
&message.from.id,
|
MessageKind::Voice { .. } => {
|
||||||
&message.from.first_name,
|
let title = utils::get_title(&message);
|
||||||
);
|
info!(
|
||||||
utils::get_files(api, message, token).await?;
|
"<{}({})>[{}({})]: *VOICE*",
|
||||||
}
|
&message.chat.id(),
|
||||||
|
title,
|
||||||
MessageKind::VideoNote { .. } => {
|
&message.from.id,
|
||||||
let title = utils::get_title(&message);
|
&message.from.first_name,
|
||||||
info!(
|
);
|
||||||
"<{}({})>[{}({})]: *VIDEO_NOTE*",
|
utils::get_files(api, message, token).await?;
|
||||||
&message.chat.id(),
|
}
|
||||||
title,
|
|
||||||
&message.from.id,
|
MessageKind::Video { .. } => {
|
||||||
&message.from.first_name,
|
let title = utils::get_title(&message);
|
||||||
);
|
info!(
|
||||||
utils::get_files(api, message, token).await?;
|
"<{}({})>[{}({})]: *VIDEO*",
|
||||||
}
|
&message.chat.id(),
|
||||||
_ => (),
|
title,
|
||||||
};
|
&message.from.id,
|
||||||
Ok(())
|
&message.from.first_name,
|
||||||
}
|
);
|
||||||
|
utils::get_files(api, message, token).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageKind::VideoNote { .. } => {
|
||||||
|
let title = utils::get_title(&message);
|
||||||
|
info!(
|
||||||
|
"<{}({})>[{}({})]: *VIDEO_NOTE*",
|
||||||
|
&message.chat.id(),
|
||||||
|
title,
|
||||||
|
&message.from.id,
|
||||||
|
&message.from.first_name,
|
||||||
|
);
|
||||||
|
utils::get_files(api, message, token).await?;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@@ -18,10 +18,9 @@ pub(crate) fn get_title(message: &Message) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn create_dir(dir: &String) {
|
pub(crate) async fn create_dir(dir: &str) {
|
||||||
match fs_create_dir(dir) {
|
if fs_create_dir(dir).is_ok() {
|
||||||
Ok(_) => info!("Dir {} created.", dir),
|
info!("Dir {} created.", dir)
|
||||||
Err(_) => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user