Word save feature.

This commit is contained in:
AB
2020-12-06 23:55:09 +03:00
parent b6f5228ce8
commit 7e57e8f706
11 changed files with 2252 additions and 116 deletions

BIN
..gitignore.un~ Normal file

Binary file not shown.

7
.gitignore~ Normal file
View File

@ -0,0 +1,7 @@
/target
memory.sqlite3
/doc
/photo
/sticker
/video
/voice

1975
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -28,4 +28,6 @@ uuid = { version = "0.8", features = ["v4"] }
sha1 = "*" sha1 = "*"
env_logger = "0.7" env_logger = "0.7"
log = { version = "^0.4.5", features = ["std"] } log = { version = "^0.4.5", features = ["std"] }
subprocess = "0.2.6"
ascii = "1.0.0"
serde_json = "1.0"

View File

@ -1,51 +1,109 @@
CREATE TABLE `word` ( --
`id` INTEGER PRIMARY KEY AUTOINCREMENT, -- File generated with SQLiteStudio v3.2.1 on Sun Dec 6 13:46:57 2020
`word` TEXT UNIQUE --
-- Text encoding used: System
--
PRAGMA foreign_keys = off;
BEGIN TRANSACTION;
-- Table: alert
CREATE TABLE IF NOT EXISTS alert (
conf_id TEXT NOT NULL,
user_id TEXT NOT NULL,
created TEXT NOT NULL,
time TEXT NOT NULL,
message TEXT
); );
CREATE TABLE sqlite_sequence(name,seq);
CREATE TABLE `user` (
`id` INTEGER NOT NULL UNIQUE, -- Table: conf
`username` TEXT NOT NULL, CREATE TABLE IF NOT EXISTS conf (
`first_name` INTEGER NOT NULL, id NUMERIC NOT NULL
`last_name` INTEGER NOT NULL, UNIQUE,
`date` INTEGER NOT NULL, title TEXT,
PRIMARY KEY(`id`) date INTEGER NOT NULL,
PRIMARY KEY (
id
)
); );
CREATE TABLE `conf` (
`id` NUMERIC NOT NULL UNIQUE,
`title` TEXT, -- Table: file
`date` INTEGER NOT NULL, CREATE TABLE IF NOT EXISTS file (
PRIMARY KEY(`id`) path TEXT NOT NULL,
user_id TEXT NOT NULL,
conf_id TEXT NOT NULL,
file_id STRING PRIMARY KEY
); );
CREATE TABLE `file` (
`path` TEXT NOT NULL UNIQUE,
`user_id` TEXT NOT NULL, -- Table: relations
`conf_id` TEXT NOT NULL, CREATE TABLE IF NOT EXISTS relations (
PRIMARY KEY(`path`) id INTEGER NOT NULL
PRIMARY KEY AUTOINCREMENT,
word_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
conf_id INTEGER NOT NULL,
date INTEGER NOT NULL,
msg_id INTEGER,
FOREIGN KEY (
word_id
)
REFERENCES word (id) ON DELETE CASCADE,
FOREIGN KEY (
user_id
)
REFERENCES user (id),
FOREIGN KEY (
conf_id
)
REFERENCES conf (id)
); );
CREATE TABLE IF NOT EXISTS "relations" (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`word_id` INTEGER NOT NULL, -- Table: reset
`user_id` INTEGER NOT NULL, CREATE TABLE IF NOT EXISTS reset (
`conf_id` INTEGER NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT,
`date` INTEGER NOT NULL, `msg_id` INTEGER NULL, user_id INTEGER,
FOREIGN KEY(`word_id`) REFERENCES `word`(`id`) ON DELETE CASCADE, conf_id INTEGER,
FOREIGN KEY(`user_id`) REFERENCES `user`(`id`), date INTEGER,
FOREIGN KEY(`conf_id`) REFERENCES `conf`(`id`) relation_id INTEGER,
FOREIGN KEY (
user_id
)
REFERENCES user (id)
); );
CREATE TABLE `reset` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`user_id` INTEGER, -- Table: user
`conf_id` INTEGER, CREATE TABLE IF NOT EXISTS user (
`date` INTEGER, id INTEGER NOT NULL
`relation_id` INTEGER, UNIQUE,
FOREIGN KEY(`user_id`) REFERENCES `user`(`id`) username TEXT,
first_name INTEGER NOT NULL,
last_name INTEGER,
date INTEGER NOT NULL,
PRIMARY KEY (
id
)
ON CONFLICT REPLACE
); );
CREATE TABLE `alert` (
`conf_id`TEXT NOT NULL,
`user_id`TEXT NOT NULL, -- Table: word
`created`TEXT NOT NULL, CREATE TABLE IF NOT EXISTS word (
`time`TEXT NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT,
`message`TEXT word TEXT UNIQUE
); );
CREATE TABLE `xxx_message` (`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `text`TEXT UNIQUE NULL);
-- Table: xxx_message
CREATE TABLE IF NOT EXISTS xxx_message (
id INTEGER NOT NULL
PRIMARY KEY AUTOINCREMENT,
text TEXT UNIQUE
);
COMMIT TRANSACTION;
PRAGMA foreign_keys = on;

BIN
mystem.exe Normal file

Binary file not shown.

View File

@ -7,7 +7,7 @@ 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();
for u in &members { for u in &members {
println!("Found user {:?}", u); debug!("Found user {:?}", u);
} }
let mut msg = "<b>I summon you</b>, ".to_string(); let mut msg = "<b>I summon you</b>, ".to_string();
for user in members { for user in members {
@ -21,10 +21,11 @@ pub(crate) async fn here(api: Api, message: Message) -> Result<(), Error> {
}; };
msg = format!("{} {}", msg, mention); msg = format!("{} {}", msg, mention);
} }
println!("Message: {:?}", msg);
api.send(message.text_reply(msg).parse_mode(ParseMode::Html)) match api.send(message.text_reply(msg).parse_mode(ParseMode::Html)).await {
.await?; Ok(_) => debug!("@here command sent to {}", message.from.id),
Err(_) => warn!("@here command sent failed to {}", message.from.id),
}
//api.send(message.chat.text("Text to message chat")).await?; //api.send(message.chat.text("Text to message chat")).await?;
//api.send(message.from.text("Private text")).await?; //api.send(message.from.text("Private text")).await?;
Ok(()) Ok(())

155
src/db.rs
View File

@ -272,60 +272,121 @@ pub(crate) async fn get_file(file_id: String) -> Result<(), errors::Error> {
} }
async fn add_word(word: String) -> Result<(), errors::Error> {
let conn = open()?;
conn.execute_named("INSERT OR IGNORE INTO word('word') VALUES (:word)", &[(":word", &word)]);
debug!("Added word {}", word);
Ok(())
}
pub(crate) async fn add_sentence(message: &telegram_bot::Message) -> Result<(), errors::Error> {
let words = utils::stemming(message).await?;
//let conn = open()?;
for word in words {
add_word(word).await?;
}
Ok(())
}
// SCHEME // SCHEME
static scheme: &str = " static scheme: &str = "
CREATE TABLE IF NOT EXISTS sqlite_sequence(name,seq); PRAGMA foreign_keys = off;
CREATE TABLE IF NOT EXISTS `word` ( BEGIN TRANSACTION;
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`word` TEXT UNIQUE -- Table: alert
CREATE TABLE IF NOT EXISTS alert (
conf_id TEXT NOT NULL,
user_id TEXT NOT NULL,
created TEXT NOT NULL,
time TEXT NOT NULL,
message TEXT
); );
CREATE TABLE IF NOT EXISTS user (
`id` INTEGER NOT NULL UNIQUE, -- Table: conf
`username` TEXT NOT NULL, CREATE TABLE IF NOT EXISTS conf (
`first_name` INTEGER NOT NULL, id NUMERIC NOT NULL
`last_name` INTEGER NOT NULL, UNIQUE,
`date` INTEGER NOT NULL, title TEXT,
PRIMARY KEY(`id`) date INTEGER NOT NULL,
PRIMARY KEY (
id
)
); );
CREATE TABLE IF NOT EXISTS `conf` (
`id` NUMERIC NOT NULL UNIQUE, -- Table: file
`title` TEXT, CREATE TABLE IF NOT EXISTS file (
`date` INTEGER NOT NULL, path TEXT NOT NULL,
PRIMARY KEY(`id`) user_id TEXT NOT NULL,
); conf_id TEXT NOT NULL,
CREATE TABLE IF NOT EXISTS `file` ( file_id STRING PRIMARY KEY
`path` TEXT NOT NULL UNIQUE,
`user_id` TEXT NOT NULL,
`conf_id` TEXT NOT NULL,
PRIMARY KEY(`path`)
); );
-- Table: relations
CREATE TABLE IF NOT EXISTS relations ( CREATE TABLE IF NOT EXISTS relations (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, id INTEGER NOT NULL
`word_id` INTEGER NOT NULL, PRIMARY KEY AUTOINCREMENT,
`user_id` INTEGER NOT NULL, word_id INTEGER NOT NULL,
`conf_id` INTEGER NOT NULL, user_id INTEGER NOT NULL,
`date` INTEGER NOT NULL, `msg_id` INTEGER NULL, conf_id INTEGER NOT NULL,
FOREIGN KEY(`word_id`) REFERENCES `word`(`id`) ON DELETE CASCADE, date INTEGER NOT NULL,
FOREIGN KEY(`user_id`) REFERENCES `user`(`id`), msg_id INTEGER,
FOREIGN KEY(`conf_id`) REFERENCES `conf`(`id`) FOREIGN KEY (
word_id
)
REFERENCES word (id) ON DELETE CASCADE,
FOREIGN KEY (
user_id
)
REFERENCES user (id),
FOREIGN KEY (
conf_id
)
REFERENCES conf (id)
); );
CREATE TABLE IF NOT EXISTS `reset` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT, -- Table: reset
`user_id` INTEGER, CREATE TABLE IF NOT EXISTS reset (
`conf_id` INTEGER, id INTEGER PRIMARY KEY AUTOINCREMENT,
`date` INTEGER, user_id INTEGER,
`relation_id` INTEGER, conf_id INTEGER,
FOREIGN KEY(`user_id`) REFERENCES `user`(`id`) date INTEGER,
relation_id INTEGER,
FOREIGN KEY (
user_id
)
REFERENCES user (id)
); );
CREATE TABLE IF NOT EXISTS `alert` (
`conf_id`TEXT NOT NULL, -- Table: user
`user_id`TEXT NOT NULL, CREATE TABLE IF NOT EXISTS user (
`created`TEXT NOT NULL, id INTEGER NOT NULL
`time`TEXT NOT NULL, UNIQUE,
`message`TEXT username TEXT,
first_name INTEGER NOT NULL,
last_name INTEGER,
date INTEGER NOT NULL,
PRIMARY KEY (
id
)
ON CONFLICT REPLACE
); );
CREATE TABLE IF NOT EXISTS `xxx_message` (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, -- Table: word
`text`TEXT UNIQUE NULL CREATE TABLE IF NOT EXISTS word (
); id INTEGER PRIMARY KEY AUTOINCREMENT,
word TEXT UNIQUE
);
-- Table: xxx_message
CREATE TABLE IF NOT EXISTS xxx_message (
id INTEGER NOT NULL
PRIMARY KEY AUTOINCREMENT,
text TEXT UNIQUE
);
COMMIT TRANSACTION;
PRAGMA foreign_keys = on;
"; ";

View File

@ -3,6 +3,7 @@ use rusqlite::Error as sqlite_error;
use rusqlite::{named_params, params, Connection, Result}; use rusqlite::{named_params, params, Connection, Result};
use std::{fmt, io, io::Error as io_error}; use std::{fmt, io, io::Error as io_error};
use telegram_bot::Error as tg_error; use telegram_bot::Error as tg_error;
use serde_json::Error as serde_error;
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum Error { pub(crate) enum Error {
@ -13,6 +14,7 @@ pub(crate) enum Error {
ConfNotFound, ConfNotFound,
IOError(io_error), IOError(io_error),
FileNotFound, FileNotFound,
JsonParseError(serde_error),
} }
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 {
@ -43,3 +45,9 @@ impl From<io_error> for Error {
return Error::IOError(e); return Error::IOError(e);
} }
} }
impl From<serde_error> for Error {
fn from(e: serde_error) -> Error {
return Error::JsonParseError(e);
}
}

View File

@ -1,4 +1,4 @@
use std::{env,process}; use std::{env, process};
use futures::StreamExt; use futures::StreamExt;
use reqwest; use reqwest;
@ -17,7 +17,6 @@ async fn handler(api: Api, message: Message, token: String) -> Result<(), errors
match message.kind { match message.kind {
MessageKind::Text { ref data, .. } => { MessageKind::Text { ref data, .. } => {
let title = utils::get_title(&message); let title = utils::get_title(&message);
info!( info!(
"<{}({})>[{}({})]: {}", "<{}({})>[{}({})]: {}",
&message.chat.id(), &message.chat.id(),
@ -26,6 +25,7 @@ async fn handler(api: Api, message: Message, token: String) -> Result<(), errors
&message.from.first_name, &message.from.first_name,
data data
); );
db::add_sentence(&message).await?;
match data.as_str() { match data.as_str() {
"/here" => commands::here(api, message).await?, "/here" => commands::here(api, message).await?,
_ => (), _ => (),
@ -58,14 +58,7 @@ async fn handler(api: Api, message: Message, token: String) -> Result<(), errors
&message.from.first_name, &message.from.first_name,
caption.clone().unwrap_or("NO_TITLE".to_string()) caption.clone().unwrap_or("NO_TITLE".to_string())
); );
/*match utils::get_files(api, message, token).await {
Ok(count) => println!("Got {} files successfully.", count),
Err(e) => println!("Couldn't get files: {:?}", e)
}
*/
utils::get_files(api, message, token).await?; utils::get_files(api, message, token).await?;
} }
MessageKind::Sticker { ref data, .. } => { MessageKind::Sticker { ref data, .. } => {
@ -129,7 +122,7 @@ async fn main() -> Result<(), errors::Error> {
Err(_) => { Err(_) => {
error!("TELEGRAM_BOT_TOKEN not set"); error!("TELEGRAM_BOT_TOKEN not set");
process::exit(0x0001); process::exit(0x0001);
}, }
}; };
let api = Api::new(token.clone()); let api = Api::new(token.clone());

View File

@ -1,6 +1,6 @@
use reqwest::Client; use reqwest::Client;
use sha1::Sha1; use sha1::Sha1;
use std::fs::{File,create_dir as fs_create_dir}; use std::fs::{create_dir as fs_create_dir, File};
use std::io::prelude::*; use std::io::prelude::*;
use std::path::Path; use std::path::Path;
use std::{env, io}; use std::{env, io};
@ -10,6 +10,16 @@ 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::{Deserialize, Serialize};
//#[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 {
@ -21,16 +31,12 @@ pub(crate) fn get_title(message: &Message) -> String {
} }
pub(crate) async fn create_dir(dir: &String) -> () { pub(crate) async fn create_dir(dir: &String) -> () {
info!("Going to create dir");
match fs_create_dir(dir) { match fs_create_dir(dir) {
Ok(_) => info!("Dir {} created.", dir), Ok(_) => info!("Dir {} created.", dir),
Err(_) => info!("Dir {} create error.", dir), Err(_) => (),
} }
info!("Going to create dir");
} }
pub(crate) async fn get_files( pub(crate) async fn get_files(
api: Api, api: Api,
message: Message, message: Message,
@ -79,7 +85,7 @@ 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(_) => {
info!("File {} exist", file_hash); debug!("File {} exist", file_hash);
} }
Err(_) => { Err(_) => {
let mut dest = File::create(path.clone())?; let mut dest = File::create(path.clone())?;
@ -88,9 +94,34 @@ pub(crate) async fn get_files(
}; };
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) => warn!("Couldn't get file: {}", e),
} }
} }
}; };
Ok(file_count) Ok(file_count)
} }
pub(crate) async fn stemming(message: &Message) -> Result<Vec<String>, errors::Error> {
let mut words: Vec<String> = vec![];
let proc = Exec::shell("mystem -d --format json -l");
match proc
.stdin(message.text().unwrap().as_str())
.communicate()
.unwrap()
.read_string()
.unwrap()
.0
{
Some(line) => {
let mut v: Vec<Value> = serde_json::from_str(line.as_str())?;
for i in v {
words.push(i["analysis"][0]["lex"].to_string().replace("\"", ""));
}
words.retain(|x| x != "null");
info!("{:?}", words);
}
None => return Ok(vec![]),
};
Ok(words)
}