Add realtions, words save feature.

This commit is contained in:
AB
2020-12-07 15:55:25 +03:00
parent 7e57e8f706
commit eb473aeddc
5 changed files with 123 additions and 70 deletions

View File

@ -1,8 +1,7 @@
use crate::db; use crate::db;
use html_escape::encode_text; use html_escape::encode_text;
use telegram_bot::prelude::*; use telegram_bot::prelude::*;
use telegram_bot::{Api, Error, Message, MessageKind, ParseMode, UpdateKind}; use telegram_bot::{Api, Error, Message, ParseMode, };
use tokio::time::delay_for;
pub(crate) async fn here(api: Api, message: Message) -> Result<(), Error> { pub(crate) async fn here(api: Api, message: Message) -> Result<(), Error> {
let members: Vec<telegram_bot::User> = db::get_members(message.chat.id()).unwrap(); let members: Vec<telegram_bot::User> = db::get_members(message.chat.id()).unwrap();
@ -22,7 +21,10 @@ pub(crate) async fn here(api: Api, message: Message) -> Result<(), Error> {
msg = format!("{} {}", msg, mention); msg = format!("{} {}", msg, mention);
} }
match api.send(message.text_reply(msg).parse_mode(ParseMode::Html)).await { match api
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
.await
{
Ok(_) => debug!("@here command sent to {}", message.from.id), Ok(_) => debug!("@here command sent to {}", message.from.id),
Err(_) => warn!("@here command sent failed to {}", message.from.id), Err(_) => warn!("@here command sent failed to {}", message.from.id),
} }

124
src/db.rs
View File

@ -1,7 +1,6 @@
use crate::errors; use crate::errors;
use crate::utils; use crate::utils;
use rusqlite::{named_params, params, Connection, Error, Result}; use rusqlite::{params, Connection, Error, Result};
use sha1::{Digest, Sha1};
use std::time::SystemTime; use std::time::SystemTime;
use telegram_bot::*; use telegram_bot::*;
@ -20,7 +19,7 @@ pub(crate) fn open() -> Result<Connection> {
pub(crate) fn update_scheme() -> Result<()> { pub(crate) fn update_scheme() -> Result<()> {
let conn = open()?; let conn = open()?;
conn.execute(scheme, params![])?; conn.execute(SCHEME, params![])?;
info!("Scheme updated."); info!("Scheme updated.");
Ok(()) Ok(())
} }
@ -57,7 +56,6 @@ pub(crate) fn get_conf(id: telegram_bot::ChatId) -> Result<Conf, errors::Error>
let mut rows = stmt.query_named(&[(":id", &id.to_string())])?; let mut rows = stmt.query_named(&[(":id", &id.to_string())])?;
let mut confs = Vec::new(); let mut confs = Vec::new();
while let Some(row) = rows.next()? { while let Some(row) = rows.next()? {
confs.push(Conf { confs.push(Conf {
id: telegram_bot::ChatId::new(row.get(0)?), id: telegram_bot::ChatId::new(row.get(0)?),
@ -65,8 +63,6 @@ pub(crate) fn get_conf(id: telegram_bot::ChatId) -> Result<Conf, errors::Error>
date: row.get(2)?, date: row.get(2)?,
}) })
} }
//println!("Confs: {:?}", confs);
if confs.len() == 0 { if confs.len() == 0 {
Err(errors::Error::ConfNotFound) Err(errors::Error::ConfNotFound)
} else { } else {
@ -74,6 +70,7 @@ pub(crate) fn get_conf(id: telegram_bot::ChatId) -> Result<Conf, errors::Error>
} }
} }
/*
pub(crate) fn get_confs() -> Result<Vec<Conf>> { pub(crate) fn get_confs() -> Result<Vec<Conf>> {
let conn = open()?; let conn = open()?;
let mut stmt = conn.prepare("SELECT id, title, date FROM conf")?; let mut stmt = conn.prepare("SELECT id, title, date FROM conf")?;
@ -92,6 +89,7 @@ pub(crate) fn get_confs() -> Result<Vec<Conf>> {
Ok(confs) Ok(confs)
} }
*/
pub(crate) fn get_members(id: telegram_bot::ChatId) -> Result<Vec<telegram_bot::User>> { pub(crate) fn get_members(id: telegram_bot::ChatId) -> Result<Vec<telegram_bot::User>> {
let conn = open()?; let conn = open()?;
@ -118,7 +116,6 @@ pub(crate) fn get_members(id: telegram_bot::ChatId) -> Result<Vec<telegram_bot::
language_code: None, language_code: None,
}) })
} }
Ok(users) Ok(users)
} }
@ -127,7 +124,7 @@ pub(crate) async fn add_conf(message: Message) -> Result<(), Error> {
let title = utils::get_title(&message); let title = utils::get_title(&message);
match get_conf(message.chat.id()) { match get_conf(message.chat.id()) {
Ok(conf) => { Ok(_) => {
let update = Conf { let update = Conf {
id: message.chat.id(), id: message.chat.id(),
title, title,
@ -143,16 +140,13 @@ pub(crate) async fn add_conf(message: Message) -> Result<(), Error> {
stmt.execute_named(&[(":id", &update.id.to_string()), (":title", &update.title)])?; stmt.execute_named(&[(":id", &update.id.to_string()), (":title", &update.title)])?;
//println!("Conf {:?} updated: {:?}", update.title, get_conf(update.id)); //println!("Conf {:?} updated: {:?}", update.title, get_conf(update.id));
} }
Err(e) => { Err(_) => {
let update = Conf { let update = Conf {
id: message.chat.id(), id: message.chat.id(),
title, title,
date: 0, date: 0,
}; };
let unix_time = SystemTime::now() let unix_time = utils::unixtime().await;
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs() as i64;
let mut stmt = conn.prepare( let mut stmt = conn.prepare(
"UPDATE conf "UPDATE conf
@ -169,7 +163,6 @@ pub(crate) async fn add_conf(message: Message) -> Result<(), Error> {
])?; ])?;
//println!("Conf {:?} added: {:?}", update.title, get_conf(update.id)); //println!("Conf {:?} added: {:?}", update.title, get_conf(update.id));
} }
_ => {}
} }
Ok(()) Ok(())
} }
@ -177,7 +170,7 @@ pub(crate) async fn add_conf(message: Message) -> Result<(), Error> {
pub(crate) async fn add_user(message: Message) -> Result<(), Error> { pub(crate) async fn add_user(message: Message) -> Result<(), Error> {
let conn = open()?; let conn = open()?;
match get_user(message.from.id) { match get_user(message.from.id) {
Ok(user) => { Ok(_) => {
let update = telegram_bot::User { let update = telegram_bot::User {
id: message.from.id, id: message.from.id,
first_name: message.from.first_name, first_name: message.from.first_name,
@ -203,7 +196,7 @@ pub(crate) async fn add_user(message: Message) -> Result<(), Error> {
])?; ])?;
//println!("User {} updated: {:?}", update.first_name, get_user(user.id)); //println!("User {} updated: {:?}", update.first_name, get_user(user.id));
} }
Err(e) => { Err(_) => {
let unix_time = SystemTime::now() let unix_time = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH) .duration_since(SystemTime::UNIX_EPOCH)
.unwrap() .unwrap()
@ -230,7 +223,6 @@ pub(crate) async fn add_user(message: Message) -> Result<(), Error> {
])?; ])?;
//println!("User added: {:?}", user); //println!("User added: {:?}", user);
} }
_ => {}
} }
Ok(()) Ok(())
} }
@ -255,44 +247,102 @@ pub(crate) async fn add_file(
Ok(()) Ok(())
} }
pub(crate) async fn get_file(file_id: String) -> Result<(), errors::Error> { pub(crate) async fn get_file(file_id: String) -> Result<i64, errors::Error> {
let conn = open()?; let conn = open()?;
let mut stmt = conn.prepare("SELECT path FROM file WHERE file_id = :file_id")?; let file_rowid = match { conn.prepare("SELECT rowid FROM file WHERE file_id = :file_id")? }
let mut rows = stmt.query_named(&[(":file_id", &file_id)])?; .query_row(params![file_id], |row| row.get(0)) {
let mut files = Vec::new(); Ok(id) => Ok(id),
Err(_) => {
Err(errors::Error::FileNotFound)
}
};
while let Some(row) = rows.next()? { file_rowid
files.push("should be rewritten"); }
async fn add_word(word: &String) -> Result<i64, errors::Error> {
match get_stop_word(&word).await {
Err(_) => return Err(errors::Error::WordInStopList),
_ => {}
} }
if files.len() > 0 { let conn = open()?;
Ok(()) let word_rowid = match { conn.prepare("INSERT OR IGNORE INTO word('word') VALUES (:word)")? }
} else { .insert(params![word])
Err(errors::Error::FileNotFound) {
Ok(id) => id,
Err(_) => { conn.prepare("SELECT rowid FROM word WHERE word = (:word)")? }
.query_row(params![word], |row| row.get(0))?,
};
Ok(word_rowid)
}
async fn get_stop_word(stop_word: &String) -> Result<(), errors::Error> {
let conn = open()?;
match conn.execute_named(
"SELECT rowid FROM stop_words WHERE word = (:stop_word)",
&[(":stop_word", &stop_word)],
) {
Ok(i) => match i {
0 => Ok(()),
_ => Err(errors::Error::WordNotFound),
},
Err(e) => Err(errors::Error::SQLITE3Error(e)),
} }
} }
async fn add_relation(word_id: i64, msg_id: i64, message: &Message) -> Result<i64, errors::Error> {
async fn add_word(word: String) -> Result<(), errors::Error> { let user_id = i64::from(message.from.id);
let conf_id = i64::from(message.chat.id());
let unix_time = utils::unixtime().await;
let conn = open()?; let conn = open()?;
conn.execute_named("INSERT OR IGNORE INTO word('word') VALUES (:word)", &[(":word", &word)]); let rowid = match {
debug!("Added word {}", word); conn.prepare(
Ok(()) "INSERT OR IGNORE INTO
relations('word_id', 'user_id', 'conf_id', 'msg_id', 'date')
VALUES (:word_id, :user_id, :conf_id, :msg_id, :date)",
)?
}
.insert(params![word_id, user_id, conf_id, msg_id, unix_time])
{
Ok(id) => id,
Err(e) => return Err(errors::Error::SQLITE3Error(e)),
};
Ok(rowid)
} }
pub(crate) async fn add_sentence(message: &telegram_bot::Message) -> Result<(), errors::Error> { pub(crate) async fn add_sentence(message: &telegram_bot::Message) -> Result<(), errors::Error> {
let text = message.text().unwrap();
let conn = open()?;
// Save sentence
let msg_rowid = match { conn.prepare("INSERT OR IGNORE INTO messages('text') VALUES (:text)")? }
.insert(params![text])
{
Ok(id) => id,
Err(_) => { conn.prepare("SELECT rowid FROM messages WHERE text = (:text)")? }
.query_row(params![text], |row| row.get(0))?,
};
// Save stemmed words
let words = utils::stemming(message).await?; let words = utils::stemming(message).await?;
//let conn = open()?;
for word in words { for word in words {
add_word(word).await?; match add_word(&word).await {
Ok(id) => {
debug!("Added {}: rowid: {}", &word, id);
match add_relation(id, msg_rowid, message).await {
Ok(_) => {},
Err(e) => panic!("SQLITE3 Error: Relations failed: {:?}", e)
}
}
Err(_) => debug!("Word {} is in stop list.", &word),
}
} }
Ok(()) Ok(())
} }
// SCHEME // SCHEME
static scheme: &str = " static SCHEME: &str = "
PRAGMA foreign_keys = off; PRAGMA foreign_keys = off;
BEGIN TRANSACTION; BEGIN TRANSACTION;

View File

@ -1,9 +1,8 @@
use reqwest::Error as reqwest_error; use reqwest::Error as reqwest_error;
use rusqlite::Error as sqlite_error; use rusqlite::Error as sqlite_error;
use rusqlite::{named_params, params, Connection, Result};
use std::{fmt, io, io::Error as io_error};
use telegram_bot::Error as tg_error;
use serde_json::Error as serde_error; use serde_json::Error as serde_error;
use std::{fmt, io::Error as io_error};
use telegram_bot::Error as tg_error;
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum Error { pub(crate) enum Error {
@ -12,6 +11,8 @@ pub(crate) enum Error {
TelegramError(tg_error), TelegramError(tg_error),
ReqwestError(reqwest_error), ReqwestError(reqwest_error),
ConfNotFound, ConfNotFound,
WordNotFound,
WordInStopList,
IOError(io_error), IOError(io_error),
FileNotFound, FileNotFound,
JsonParseError(serde_error), JsonParseError(serde_error),

View File

@ -1,8 +1,6 @@
use std::{env, process}; use std::{env, process};
use futures::StreamExt; use futures::StreamExt;
use reqwest;
use telegram_bot::types::chat::MessageChat;
use telegram_bot::*; use telegram_bot::*;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
@ -33,7 +31,6 @@ async fn handler(api: Api, message: Message, token: String) -> Result<(), errors
} }
MessageKind::Photo { MessageKind::Photo {
ref caption, ref caption,
ref data,
.. ..
} => { } => {
let title = utils::get_title(&message); let title = utils::get_title(&message);
@ -61,7 +58,7 @@ async fn handler(api: Api, message: Message, token: String) -> Result<(), errors
utils::get_files(api, message, token).await?; utils::get_files(api, message, token).await?;
} }
MessageKind::Sticker { ref data, .. } => { MessageKind::Sticker { .. } => {
let title = utils::get_title(&message); let title = utils::get_title(&message);
info!( info!(
"<{}({})>[{}({})]: *STICKER*", "<{}({})>[{}({})]: *STICKER*",
@ -115,8 +112,11 @@ async fn handler(api: Api, message: Message, token: String) -> Result<(), errors
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), errors::Error> { async fn main() -> Result<(), errors::Error> {
env_logger::from_env(Env::default().default_filter_or("debug")).init(); env_logger::from_env(Env::default().default_filter_or("info")).init();
db::update_scheme(); match db::update_scheme() {
Ok(_) => {},
Err(e) => panic!("Database error: {:?}", e)
}
let token = match env::var("TELEGRAM_BOT_TOKEN") { let token = match env::var("TELEGRAM_BOT_TOKEN") {
Ok(token) => token, Ok(token) => token,
Err(_) => { Err(_) => {
@ -125,7 +125,6 @@ async fn main() -> Result<(), errors::Error> {
} }
}; };
let api = Api::new(token.clone()); let api = Api::new(token.clone());
// Fetch new updates via long poll method // Fetch new updates via long poll method
let mut stream = api.stream(); let mut stream = api.stream();
while let Some(update) = stream.next().await { while let Some(update) = stream.next().await {
@ -134,7 +133,6 @@ async fn main() -> Result<(), errors::Error> {
if let UpdateKind::Message(message) = update.kind { if let UpdateKind::Message(message) = update.kind {
db::add_user(message.clone()).await?; db::add_user(message.clone()).await?;
db::add_conf(message.clone()).await?; db::add_conf(message.clone()).await?;
handler(api.clone(), message, token.clone()).await?; handler(api.clone(), message, token.clone()).await?;
} }
} }

View File

@ -1,31 +1,21 @@
use reqwest::Client;
use sha1::Sha1; use sha1::Sha1;
use std::fs::{create_dir as fs_create_dir, File}; use std::fs::{create_dir as fs_create_dir, File};
use std::io::prelude::*; use std::io::prelude::*;
use std::path::Path; use std::time::SystemTime;
use std::{env, io};
use telegram_bot::*; use telegram_bot::*;
use uuid::Uuid; use uuid::Uuid;
use crate::db; use crate::db;
use crate::errors; use crate::errors;
extern crate reqwest; extern crate reqwest;
use ascii::AsciiChar::{LineFeed, EOT};
use subprocess::{Exec, Popen, PopenConfig, Redirection};
use serde_json::Value; use serde_json::Value;
//use serde::{Deserialize, Serialize}; use subprocess::{Exec, };
//#[derive(Serialize, Deserialize)]
struct StemWord {
}
pub(crate) fn get_title(message: &Message) -> String { pub(crate) fn get_title(message: &Message) -> String {
match &message.chat { match &message.chat {
MessageChat::Supergroup(chat) => chat.title.clone(), MessageChat::Supergroup(chat) => chat.title.clone(),
MessageChat::Group(chat) => chat.title.clone(), MessageChat::Group(chat) => chat.title.clone(),
MessageChat::Private(chat) => "PRIVATE".to_string(), MessageChat::Private(_) => format!("PRIVATE"),
_ => "PRIVATE".to_string(), _ => "PRIVATE".to_string(),
} }
} }
@ -37,6 +27,13 @@ pub(crate) async fn create_dir(dir: &String) -> () {
} }
} }
pub(crate) async fn unixtime() -> i64 {
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs() as i64
}
pub(crate) async fn get_files( pub(crate) async fn get_files(
api: Api, api: Api,
message: Message, message: Message,
@ -66,7 +63,7 @@ pub(crate) async fn get_files(
token, token,
api_response.file_path.unwrap() api_response.file_path.unwrap()
); );
let mut file_response = reqwest::get(&url).await?; let file_response = reqwest::get(&url).await?;
let ext = { let ext = {
file_response file_response
.url() .url()
@ -85,16 +82,18 @@ pub(crate) async fn get_files(
let file_hash = hasher.digest().to_string(); let file_hash = hasher.digest().to_string();
match db::get_file(file_hash.clone()).await { match db::get_file(file_hash.clone()).await {
Ok(_) => { Ok(_) => {
debug!("File {} exist", file_hash);
} }
Err(_) => { Err(_) => {
let mut dest = File::create(path.clone())?; let mut dest = File::create(path.clone())?;
dest.write(&content); match dest.write(&content) {
Ok(_) => {},
Err(e) => panic!("IO Error: Couldn't save file: {:?}", e)
}
} }
}; };
db::add_file(&message, path, file_hash).await?; db::add_file(&message, path, file_hash).await?;
} }
Err(e) => warn!("Couldn't get file: {}", e), Err(e) => error!("Couldn't get file: {}", e),
} }
} }
}; };
@ -113,12 +112,15 @@ pub(crate) async fn stemming(message: &Message) -> Result<Vec<String>, errors::E
.0 .0
{ {
Some(line) => { Some(line) => {
let mut v: Vec<Value> = serde_json::from_str(line.as_str())?; let v: Vec<Value> = match serde_json::from_str(line.as_str()) {
Ok(val) => val,
Err(_) => return Ok(vec![]),
};
for i in v { for i in v {
words.push(i["analysis"][0]["lex"].to_string().replace("\"", "")); words.push(i["analysis"][0]["lex"].to_string().replace("\"", ""));
} }
words.retain(|x| x != "null"); words.retain(|x| x != "null");
info!("{:?}", words); //debug!("Parsed words: {}.", words.join(", "));
} }
None => return Ok(vec![]), None => return Ok(vec![]),
}; };