mirror of
https://github.com/house-of-vanity/desubot.git
synced 2025-07-08 04:54:08 +00:00
Compare commits
44 Commits
Author | SHA1 | Date | |
---|---|---|---|
f97562e9b7 | |||
2d000101c2 | |||
a26d227190 | |||
cc44f0e23b | |||
96df636195 | |||
a48e25800c | |||
36660d384d | |||
0d24976ec2 | |||
6ae3b2af1f | |||
a39f6a8c2a | |||
788c2cbbd4 | |||
9d5e5a3217 | |||
945da05794 | |||
3085d4c450 | |||
4b142ae8ef | |||
8f3cccf01d | |||
3136bce84f | |||
e09047bb5b | |||
5528177e52 | |||
ed32bd9195 | |||
d14aa3beb4 | |||
43e4f26af1 | |||
5d8d3441d2 | |||
34fa54e6f4 | |||
d5b30cc94e | |||
7a66034381 | |||
47906fe22d | |||
ea6d9b55a1 | |||
83a6045b18 | |||
c8c55782ec | |||
a1b272bd40 | |||
ed68dbd4bd | |||
3f00505659 | |||
5a41d4a0b9 | |||
3fd5b124f3 | |||
17442819c4 | |||
7adc629292 | |||
39640139fa | |||
0812c9e371 | |||
f111f54606 | |||
7e17851131 | |||
b674ae5b15 | |||
412c3f313c | |||
1838674cab |
27
.github/workflows/automerge.yml
vendored
Normal file
27
.github/workflows/automerge.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
name: automerge
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- labeled
|
||||
- unlabeled
|
||||
- synchronize
|
||||
- opened
|
||||
- edited
|
||||
- ready_for_review
|
||||
- reopened
|
||||
- unlocked
|
||||
pull_request_review:
|
||||
types:
|
||||
- submitted
|
||||
check_suite:
|
||||
types:
|
||||
- completed
|
||||
status: {}
|
||||
jobs:
|
||||
automerge:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: automerge
|
||||
uses: "pascalgn/automerge-action@v0.13.0"
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ memory.sqlite3
|
||||
/video
|
||||
/voice
|
||||
/.idea
|
||||
Cargo.lock
|
19
Cargo.toml
19
Cargo.toml
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "desubot"
|
||||
version = "0.1.0"
|
||||
version = "0.5.1"
|
||||
authors = ["AB <ab@hexor.ru>"]
|
||||
edition = "2018"
|
||||
|
||||
@ -9,28 +9,33 @@ edition = "2018"
|
||||
[dependencies]
|
||||
bytes = "0.5"
|
||||
tokio = { version = "0.2", features = ["full"]}
|
||||
|
||||
tracing = "0.1.9"
|
||||
tracing-futures = "0.2"
|
||||
multipart = { version = "0.16", default-features = false, features = ["client"] }
|
||||
|
||||
telegram-bot = "0.8.0"
|
||||
|
||||
silicon = "0.4.0"
|
||||
hyper = "0.13"
|
||||
hyper-tls = { version = "0.4", optional = true }
|
||||
futures = "0.3"
|
||||
hyper-rustls = { version = "0.19", optional = true }
|
||||
|
||||
rusqlite = { version = "0.24.2", features = ["bundled"]}
|
||||
html-escape = "0.2"
|
||||
regex = "1"
|
||||
reqwest = "0.10.9"
|
||||
uuid = { version = "0.8", features = ["v4"] }
|
||||
sha1 = "*"
|
||||
sha1 = "0.6.0"
|
||||
env_logger = "0.7"
|
||||
log = { version = "^0.4.5", features = ["std"] }
|
||||
subprocess = "0.2.6"
|
||||
serde_json = "1.0"
|
||||
markov = "1.1.0"
|
||||
rand = "0.7.3"
|
||||
mystem = "0.2"
|
||||
mystem = "^0.2"
|
||||
#mystem = { path = "../mystem-rs" }
|
||||
async-trait = "0.1.42"
|
||||
sqlparser = "0.7.0"
|
||||
|
||||
[dependencies.syntect]
|
||||
version = "4.4"
|
||||
default-features = false
|
||||
features = ["parsing", "dump-load", "regex-onig"]
|
4
README
4
README
@ -7,9 +7,7 @@ Telegram bot with light group statistic and heavy spy features.
|
||||
* /here command to mention all members.
|
||||
* Alongside with saving whole message bot perform blacklist filter and stemming for every word (only Russian). "Красивую собаку мыли негры" -> "красивый собака мыть негр"
|
||||
* Generate sentences using Markov Chains trained on history with /markov_all.
|
||||
|
||||
== TODO ==
|
||||
* Syntax highlighting for code exported to image.
|
||||
* Syntax highlighting for CODE exported to image.
|
||||
|
||||
== Important ==
|
||||
* Desubot uses MyStem by Yandex for word stemming and assume that mystem binary is available in PATH.
|
||||
|
3
assets/README.md
Normal file
3
assets/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Assets
|
||||
|
||||
Silicon uses [bat](https://github.com/sharkdp/bat/tree/master/assets)'s syntax and theme resources.
|
BIN
assets/fonts/Hack-Bold.ttf
Normal file
BIN
assets/fonts/Hack-Bold.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Hack-BoldItalic.ttf
Normal file
BIN
assets/fonts/Hack-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Hack-Italic.ttf
Normal file
BIN
assets/fonts/Hack-Italic.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Hack-Regular.ttf
Normal file
BIN
assets/fonts/Hack-Regular.ttf
Normal file
Binary file not shown.
43
assets/help_text.rs
Normal file
43
assets/help_text.rs
Normal file
@ -0,0 +1,43 @@
|
||||
#[allow(dead_code)]
|
||||
static CODE_HELP: &str = "<b>Code highlighter</b>
|
||||
|
||||
<i>Usage</i>
|
||||
<pre>/code
|
||||
<CODE>
|
||||
#<lang - JS by default> #<theme - Dracula 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
|
||||
";
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub static SQL_HELP: &str = "<b>Perform an SQL command</b>
|
||||
<i>* Only one sentence per message.
|
||||
* Only SELECT command.
|
||||
* Max result length is 100 lines. Use LIMIT 100.
|
||||
* SQLITE syntax is available only.</i>";
|
21
assets/sync_from_bat.py
Normal file
21
assets/sync_from_bat.py
Normal file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python
|
||||
# Sync themes and syntaxes from [bat](https://github.com/sharkdp/bat/tree/master/assets)
|
||||
|
||||
import os
|
||||
from glob import glob
|
||||
from shutil import copy
|
||||
|
||||
if not os.path.exists('../../bat'):
|
||||
os.system('git clone https://github.com/sharkdp/bat ../../bat')
|
||||
else:
|
||||
os.system('git -C ../../bat pull')
|
||||
|
||||
for syntax_file in glob('../../bat/assets/syntaxes/**/*.sublime-syntax'):
|
||||
copy(syntax_file, './syntaxes/')
|
||||
|
||||
for theme_file in glob('../../bat/assets/themes/**/*.tmTheme'):
|
||||
copy(theme_file, './themes/')
|
||||
|
||||
os.system('bat cache --build --source . --target .')
|
||||
|
||||
print('Finished.')
|
BIN
assets/syntaxes.bin
Normal file
BIN
assets/syntaxes.bin
Normal file
Binary file not shown.
4
assets/syntaxes/.gitignore
vendored
Normal file
4
assets/syntaxes/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
BIN
assets/themes.bin
Normal file
BIN
assets/themes.bin
Normal file
Binary file not shown.
5
assets/themes/.gitignore
vendored
Normal file
5
assets/themes/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
!Dracula.tmTheme
|
940
assets/themes/Dracula.tmTheme
Normal file
940
assets/themes/Dracula.tmTheme
Normal file
@ -0,0 +1,940 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- Dracula Theme v1.4.3
|
||||
#
|
||||
# https://github.com/dracula/sublime
|
||||
#
|
||||
# Copyright 2013-present, All rights reserved
|
||||
#
|
||||
# Code licensed under the MIT license
|
||||
#
|
||||
# @author Zeno Rocha <hi@zenorocha.com>
|
||||
-->
|
||||
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Dracula</string>
|
||||
<key>settings</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#282a36</string>
|
||||
<key>caret</key>
|
||||
<string>#f8f8f0</string>
|
||||
<key>block_caret</key>
|
||||
<string>#999a9e</string>
|
||||
<key>foreground</key>
|
||||
<string>#f8f8f2</string>
|
||||
<key>invisibles</key>
|
||||
<string>#3B3A32</string>
|
||||
<key>lineHighlight</key>
|
||||
<string>#44475a</string>
|
||||
<key>selection</key>
|
||||
<string>#44475a</string>
|
||||
<key>findHighlight</key>
|
||||
<string>#effb7b</string>
|
||||
<key>findHighlightForeground</key>
|
||||
<string>#000000</string>
|
||||
<key>selectionBorder</key>
|
||||
<string>#222218</string>
|
||||
<key>activeGuide</key>
|
||||
<string>#9D550FB0</string>
|
||||
<key>bracketsForeground</key>
|
||||
<string>#F8F8F2A5</string>
|
||||
<key>bracketsOptions</key>
|
||||
<string>underline</string>
|
||||
<key>bracketContentsForeground</key>
|
||||
<string>#F8F8F2A5</string>
|
||||
<key>bracketContentsOptions</key>
|
||||
<string>underline</string>
|
||||
<key>tagsOptions</key>
|
||||
<string>stippled_underline</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Comment</string>
|
||||
<key>scope</key>
|
||||
<string>comment</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#6272a4</string>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>String</string>
|
||||
<key>scope</key>
|
||||
<string>string</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#f1fa8c</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Number</string>
|
||||
<key>scope</key>
|
||||
<string>constant.numeric</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#bd93f9</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Built-in constant</string>
|
||||
<key>scope</key>
|
||||
<string>constant.language</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#bd93f9</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>User-defined constant</string>
|
||||
<key>scope</key>
|
||||
<string>constant.character, constant.other</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#bd93f9</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Variable</string>
|
||||
<key>scope</key>
|
||||
<string>variable</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Ruby's @variable</string>
|
||||
<key>scope</key>
|
||||
<string>variable.other.readwrite.instance</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#ffb86c</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>String interpolation</string>
|
||||
<key>scope</key>
|
||||
<string>constant.character.escaped, constant.character.escape, string source, string source.ruby</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#ff79c6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Ruby Regexp</string>
|
||||
<key>scope</key>
|
||||
<string>source.ruby string.regexp.classic.ruby,source.ruby string.regexp.mod-r.ruby</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#ff5555</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Keyword</string>
|
||||
<key>scope</key>
|
||||
<string>keyword</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#ff79c6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Storage</string>
|
||||
<key>scope</key>
|
||||
<string>storage</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#ff79c6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Storage type</string>
|
||||
<key>scope</key>
|
||||
<string>storage.type</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#8be9fd</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Storage Type Namespace</string>
|
||||
<key>scope</key>
|
||||
<string>storage.type.namespace</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#8be9fd</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Storage Type Class</string>
|
||||
<key>scope</key>
|
||||
<string>storage.type.class</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#ff79c6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Class name</string>
|
||||
<key>scope</key>
|
||||
<string>entity.name.class</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>underline</string>
|
||||
<key>foreground</key>
|
||||
<string>#8be9fd</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Meta Path</string>
|
||||
<key>scope</key>
|
||||
<string>meta.path</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>underline</string>
|
||||
<key>foreground</key>
|
||||
<string>#66d9ef</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Inherited class</string>
|
||||
<key>scope</key>
|
||||
<string>entity.other.inherited-class</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic underline</string>
|
||||
<key>foreground</key>
|
||||
<string>#8be9fd</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Function name</string>
|
||||
<key>scope</key>
|
||||
<string>entity.name.function</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#50fa7b</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Function argument</string>
|
||||
<key>scope</key>
|
||||
<string>variable.parameter</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#ffb86c</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Tag name</string>
|
||||
<key>scope</key>
|
||||
<string>entity.name.tag</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#ff79c6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Tag attribute</string>
|
||||
<key>scope</key>
|
||||
<string>entity.other.attribute-name</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#50fa7b</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Library function</string>
|
||||
<key>scope</key>
|
||||
<string>support.function</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#8be9fd</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Library constant</string>
|
||||
<key>scope</key>
|
||||
<string>support.constant</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#6be5fd</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Library class/type</string>
|
||||
<key>scope</key>
|
||||
<string>support.type, support.class</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#66d9ef</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Library variable</string>
|
||||
<key>scope</key>
|
||||
<string>support.other.variable</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Support Other Namespace</string>
|
||||
<key>scope</key>
|
||||
<string>support.other.namespace</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#66d9ef</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Invalid</string>
|
||||
<key>scope</key>
|
||||
<string>invalid</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#ff79c6</string>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F0</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Invalid deprecated</string>
|
||||
<key>scope</key>
|
||||
<string>invalid.deprecated</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#bd93f9</string>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F0</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>JSON String</string>
|
||||
<key>scope</key>
|
||||
<string>meta.structure.dictionary.json string.quoted.double.json</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#CFCFC2</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>diff.header</string>
|
||||
<key>scope</key>
|
||||
<string>meta.diff, meta.diff.header</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#6272a4</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>diff.deleted</string>
|
||||
<key>scope</key>
|
||||
<string>markup.deleted</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#ff79c6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>diff.inserted</string>
|
||||
<key>scope</key>
|
||||
<string>markup.inserted</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#50fa7b</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>diff.changed</string>
|
||||
<key>scope</key>
|
||||
<string>markup.changed</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#E6DB74</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>scope</key>
|
||||
<string>constant.numeric.line-number.find-in-files - match</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#bd93f9</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>scope</key>
|
||||
<string>entity.name.filename</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#E6DB74</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>scope</key>
|
||||
<string>message.error</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#F83333</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>JSON Punctuation</string>
|
||||
<key>scope</key>
|
||||
<string>punctuation.definition.string.begin.json - meta.structure.dictionary.value.json, punctuation.definition.string.end.json - meta.structure.dictionary.value.json</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#EEEEEE</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>JSON Structure</string>
|
||||
<key>scope</key>
|
||||
<string>meta.structure.dictionary.json string.quoted.double.json</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8be9fd</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>JSON String</string>
|
||||
<key>scope</key>
|
||||
<string>meta.structure.dictionary.value.json string.quoted.double.json</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#f1fa8c</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>JSON: 6 deep</string>
|
||||
<key>scope</key>
|
||||
<string>meta meta meta meta meta meta meta.structure.dictionary.value string</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#50fa7b</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>JSON: 5 deep</string>
|
||||
<key>scope</key>
|
||||
<string>meta meta meta meta meta meta.structure.dictionary.value string</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#ffb86c</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>JSON: 4 deep</string>
|
||||
<key>scope</key>
|
||||
<string>meta meta meta meta meta.structure.dictionary.value string</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#ff79c6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>JSON: 3 deep</string>
|
||||
<key>scope</key>
|
||||
<string>meta meta meta meta.structure.dictionary.value string</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#bd93f9</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>JSON: 2 deep</string>
|
||||
<key>scope</key>
|
||||
<string>meta meta meta.structure.dictionary.value string</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#50fa7b</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>JSON: 1 deep</string>
|
||||
<key>scope</key>
|
||||
<string>meta meta.structure.dictionary.value string</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#ffb86c</string>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
<!-- Markdown Tweaks -->
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup: strike</string>
|
||||
<key>scope</key>
|
||||
<string>markup.strike</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#FFB86C</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup: bold</string>
|
||||
<key>scope</key>
|
||||
<string>markup.bold</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>bold</string>
|
||||
<key>foreground</key>
|
||||
<string>#FFB86C</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup: italic</string>
|
||||
<key>scope</key>
|
||||
<string>markup.italic</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#FFB86C</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markdown: heading</string>
|
||||
<key>scope</key>
|
||||
<string>markup.heading</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8BE9FD</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markdown: List Items Punctuation</string>
|
||||
<key>scope</key>
|
||||
<string>punctuation.definition.list_item.markdown</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#FF79C6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markdown: Blockquote</string>
|
||||
<key>scope</key>
|
||||
<string>markup.quote</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#6272A4</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markdown: Blockquote Punctuation</string>
|
||||
<key>scope</key>
|
||||
<string>punctuation.definition.blockquote.markdown</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>background</key>
|
||||
<string>#6272A4</string>
|
||||
<key>foreground</key>
|
||||
<string>#6272A4</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markdown: Separator</string>
|
||||
<key>scope</key>
|
||||
<string>meta.separator</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#6272A4</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup: raw inline</string>
|
||||
<key>scope</key>
|
||||
<string>text.html.markdown markup.raw.inline</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#50FA7B</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup: underline</string>
|
||||
<key>scope</key>
|
||||
<string>markup.underline</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>underline</string>
|
||||
<key>foreground</key>
|
||||
<string>#BD93F9</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup: Raw block</string>
|
||||
<key>scope</key>
|
||||
<string>markup.raw.block</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#CFCFC2</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markdown: Raw Block fenced source</string>
|
||||
<key>scope</key>
|
||||
<string>markup.raw.block.fenced.markdown source</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F2</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markdown: Fenced Bode Block</string>
|
||||
<key>scope</key>
|
||||
<string>punctuation.definition.fenced.markdown, variable.language.fenced.markdown</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#6272A4</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markdown: Fenced Language</string>
|
||||
<key>scope</key>
|
||||
<string>variable.language.fenced.markdown</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#6272A4</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Punctuation Accessor</string>
|
||||
<key>scope</key>
|
||||
<string>punctuation.accessor</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#FF79C6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Meta Function Return Type</string>
|
||||
<key>scope</key>
|
||||
<string>meta.function.return-type</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#FF79C6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Punctuation Section Block Begin</string>
|
||||
<key>scope</key>
|
||||
<string>punctuation.section.block.begin</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#ffffff</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Punctuation Section Block End</string>
|
||||
<key>scope</key>
|
||||
<string>punctuation.section.block.end</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#ffffff</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Punctuation Section Embedded Begin</string>
|
||||
<key>scope</key>
|
||||
<string>punctuation.section.embedded.begin</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#ff79c6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Punctuation Section Embedded End</string>
|
||||
<key>scope</key>
|
||||
<string>punctuation.section.embedded.end</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#ff79c6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Punctuation Separator Namespace</string>
|
||||
<key>scope</key>
|
||||
<string>punctuation.separator.namespace</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#ff79c6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Variable Function</string>
|
||||
<key>scope</key>
|
||||
<string>variable.function</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#50fa7b</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Variable Other</string>
|
||||
<key>scope</key>
|
||||
<string>variable.other</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#ffffff</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Variable Language</string>
|
||||
<key>scope</key>
|
||||
<string>variable.language</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#bd93f9</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Entity Name Module Ruby</string>
|
||||
<key>scope</key>
|
||||
<string>entity.name.module.ruby</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8be9fd</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Entity Name Constant Ruby</string>
|
||||
<key>scope</key>
|
||||
<string>entity.name.constant.ruby</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#bd93f9</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Support Function Builtin Ruby</string>
|
||||
<key>scope</key>
|
||||
<string>support.function.builtin.ruby</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#ffffff</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Storage Type Namespace CS</string>
|
||||
<key>scope</key>
|
||||
<string>storage.type.namespace.cs</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#ff79c6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Entity Name Namespace CS</string>
|
||||
<key>scope</key>
|
||||
<string>entity.name.namespace.cs</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8be9fd</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
<key>uuid</key>
|
||||
<string>83091B89-765E-4F0D-9275-0EC6CB084126</string>
|
||||
<key>colorSpaceName</key>
|
||||
<string>sRGB</string>
|
||||
<key>semanticClass</key>
|
||||
<string>theme.dracula</string>
|
||||
<key>author</key>
|
||||
<string>Zeno Rocha</string>
|
||||
</dict>
|
||||
</plist>
|
844
src/commands.rs
844
src/commands.rs
@ -1,254 +1,646 @@
|
||||
#![allow(unused_variables)]
|
||||
use crate::db;
|
||||
use crate::errors::Error;
|
||||
use crate::errors::Error::{CodeHighlightningError, SQLITE3Error, SQLInvalidCommand};
|
||||
use async_trait::async_trait;
|
||||
use html_escape::encode_text;
|
||||
use markov::Chain;
|
||||
use mystem::Case::Nominative;
|
||||
use mystem::Gender::Feminine;
|
||||
use mystem::MyStem;
|
||||
use mystem::Person::First;
|
||||
use mystem::Tense::{Inpresent, Past};
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::Rng;
|
||||
use regex::Regex;
|
||||
use sqlparser::ast::Statement;
|
||||
use sqlparser::dialect::GenericDialect;
|
||||
use sqlparser::parser::Parser;
|
||||
use syntect::easy::HighlightLines;
|
||||
use syntect::highlighting::Theme;
|
||||
use syntect::parsing::SyntaxReference;
|
||||
use syntect::util::LinesWithEndings;
|
||||
use telegram_bot::prelude::*;
|
||||
use telegram_bot::{Api, Message, ParseMode};
|
||||
|
||||
pub(crate) async fn here(api: Api, message: Message) -> Result<(), Error> {
|
||||
let members: Vec<telegram_bot::User> = db::get_members(message.chat.id()).unwrap();
|
||||
for u in &members {
|
||||
debug!("Found user {:?} in chat {}", u, message.chat.id());
|
||||
}
|
||||
let mut msg = "<b>I summon you</b>, ".to_string();
|
||||
for user in members {
|
||||
let mention = match user.username {
|
||||
Some(username) => format!("@{}", username),
|
||||
_ => format!(
|
||||
"<a href=\"tg://user?id={}\">{}</a>",
|
||||
encode_text(&user.id.to_string()),
|
||||
encode_text(&user.first_name)
|
||||
),
|
||||
};
|
||||
msg = format!("{} {}", msg, mention);
|
||||
}
|
||||
include!("../assets/help_text.rs");
|
||||
|
||||
match api
|
||||
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
||||
.await
|
||||
{
|
||||
Ok(_) => debug!("/here command sent to {}", message.chat.id()),
|
||||
Err(_) => warn!("/here command sent failed to {}", message.chat.id()),
|
||||
}
|
||||
//api.send(message.chat.text("Text to message chat")).await?;
|
||||
//api.send(message.from.text("Private text")).await?;
|
||||
Ok(())
|
||||
pub struct Here {
|
||||
pub data: String,
|
||||
}
|
||||
pub struct Top {
|
||||
pub data: String,
|
||||
}
|
||||
pub struct MarkovAll {
|
||||
pub data: String,
|
||||
}
|
||||
pub struct Markov {
|
||||
pub data: String,
|
||||
}
|
||||
pub struct Omedeto {
|
||||
pub data: String,
|
||||
}
|
||||
pub struct Sql {
|
||||
pub data: String,
|
||||
}
|
||||
pub struct Code {
|
||||
pub data: String,
|
||||
}
|
||||
|
||||
pub(crate) async fn top(api: Api, message: Message) -> Result<(), Error> {
|
||||
let top = db::get_top(&message).await?;
|
||||
let mut msg = "<b>Your top using words:</b>\n<pre>".to_string();
|
||||
let mut counter = 1;
|
||||
for word in top.iter() {
|
||||
msg = format!(
|
||||
"{} <b>{}</b> {} - {}\n",
|
||||
msg, counter, word.word, word.count
|
||||
);
|
||||
counter += 1;
|
||||
}
|
||||
msg = format!("{}{}", msg, "</pre>");
|
||||
match api
|
||||
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
||||
.await
|
||||
{
|
||||
Ok(_) => debug!("/top command sent to {}", message.chat.id()),
|
||||
Err(_) => warn!("/top command sent failed to {}", message.chat.id()),
|
||||
}
|
||||
//api.send(message.chat.text("Text to message chat")).await?;
|
||||
//api.send(message.from.text("Private text")).await?;
|
||||
Ok(())
|
||||
#[async_trait]
|
||||
pub trait Execute {
|
||||
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error>;
|
||||
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error>;
|
||||
async fn exec_mystem(
|
||||
&self,
|
||||
api: &Api,
|
||||
message: &Message,
|
||||
mystem: &mut MyStem,
|
||||
) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
pub(crate) async fn markov_all(api: Api, message: Message) -> Result<(), Error> {
|
||||
let messages = db::get_messages_random_all().await?;
|
||||
let mut chain = Chain::new();
|
||||
chain.feed(messages);
|
||||
let mut sentences = chain.generate();
|
||||
let mut msg = String::new();
|
||||
for _ in 1..rand::thread_rng().gen_range(2, 10) {
|
||||
msg = format!("{} {}", msg, sentences.pop().unwrap());
|
||||
#[async_trait]
|
||||
impl Execute for Sql {
|
||||
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
match api
|
||||
.send(message.text_reply(msg.trim()).parse_mode(ParseMode::Html))
|
||||
.await
|
||||
{
|
||||
Ok(_) => debug!("/markov_all command sent to {}", message.chat.id()),
|
||||
Err(_) => warn!("/markov_all command sent failed to {}", message.chat.id()),
|
||||
}
|
||||
//api.send(message.chat.text("Text to message chat")).await?;
|
||||
//api.send(message.from.text("Private text")).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn markov(api: Api, message: Message) -> Result<(), Error> {
|
||||
let messages = db::get_messages_random_group(&message).await?;
|
||||
let mut chain = Chain::new();
|
||||
chain.feed(messages);
|
||||
let mut sentences = chain.generate();
|
||||
let mut msg = String::new();
|
||||
for _ in 1..rand::thread_rng().gen_range(2, 10) {
|
||||
msg = format!("{} {}", msg, sentences.pop().unwrap());
|
||||
}
|
||||
match api
|
||||
.send(message.text_reply(msg.trim()).parse_mode(ParseMode::Html))
|
||||
.await
|
||||
{
|
||||
Ok(_) => debug!("/markov command sent to {}", message.chat.id()),
|
||||
Err(_) => warn!("/markov command sent failed to {}", message.chat.id()),
|
||||
}
|
||||
//api.send(message.chat.text("Text to message chat")).await?;
|
||||
//api.send(message.from.text("Private text")).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn omedeto(api: Api, message: Message, mystem: &mut MyStem) -> Result<(), Error> {
|
||||
let all_msg = db::get_messages_user_all(&message).await?;
|
||||
let re = Regex::new(r"^[яЯ] [а-яА-Я]+(-[а-яА-Я]+(_[а-яА-Я]+)*)*$").unwrap();
|
||||
let mut nouns: Vec<String> = all_msg
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter(|m| re.is_match(m))
|
||||
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||
.filter(|m| {
|
||||
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
||||
if stem.is_empty() {
|
||||
false
|
||||
} else if stem[0].lex.is_empty() {
|
||||
false
|
||||
} else {
|
||||
match stem[0].lex[0].grammem.part_of_speech {
|
||||
mystem::PartOfSpeech::Noun => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
nouns.sort();
|
||||
nouns.dedup();
|
||||
nouns.shuffle(&mut rand::thread_rng());
|
||||
|
||||
let mut verbs_p: Vec<String> = all_msg
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter(|m| re.is_match(m))
|
||||
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||
.filter(|m| {
|
||||
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
||||
if stem.is_empty() {
|
||||
false
|
||||
} else if stem[0].lex.is_empty() {
|
||||
false
|
||||
} else {
|
||||
match stem[0].lex[0].grammem.part_of_speech {
|
||||
mystem::PartOfSpeech::Verb => stem[0].lex[0]
|
||||
.grammem
|
||||
.facts
|
||||
.contains(&mystem::Fact::Tense(Past)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
verbs_p.sort();
|
||||
verbs_p.dedup();
|
||||
verbs_p.shuffle(&mut rand::thread_rng());
|
||||
|
||||
let mut verbs_i: Vec<String> = all_msg
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter(|m| re.is_match(m))
|
||||
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||
.filter(|m| {
|
||||
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
||||
if stem.is_empty() {
|
||||
false
|
||||
} else if stem[0].lex.is_empty() {
|
||||
false
|
||||
} else {
|
||||
match stem[0].lex[0].grammem.part_of_speech {
|
||||
mystem::PartOfSpeech::Verb => stem[0].lex[0]
|
||||
.grammem
|
||||
.facts
|
||||
.contains(&mystem::Fact::Tense(Inpresent)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
verbs_i.sort();
|
||||
verbs_i.dedup();
|
||||
verbs_i.shuffle(&mut rand::thread_rng());
|
||||
|
||||
if nouns.is_empty() {
|
||||
nouns.push(message.from.first_name.to_string());
|
||||
}
|
||||
let start: Vec<String> = vec![
|
||||
"С новыйм годом.".into(),
|
||||
"С НГ тебя".into(),
|
||||
"Поздравляю".into(),
|
||||
"Поздравляю с НГ".into(),
|
||||
];
|
||||
//debug!("Nouns: {:#?}", nouns);
|
||||
//debug!("Verbs: {:#?}", verbs);
|
||||
|
||||
let fem = {
|
||||
let z = mystem
|
||||
.stemming(message.from.first_name.to_string())
|
||||
.unwrap();
|
||||
|
||||
if z.is_empty() {
|
||||
false
|
||||
} else if z[0].lex.is_empty() {
|
||||
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||
let mut sql = self.data.clone();
|
||||
debug!("PIZDA - {}", sql);
|
||||
if sql == "/sql" || sql == "/sql-" {
|
||||
return Ok(SQL_HELP.to_string())
|
||||
}
|
||||
let is_head = if sql.starts_with('-') {
|
||||
sql = sql.replacen("-", "", 1);
|
||||
false
|
||||
} else {
|
||||
if z[0].lex[0]
|
||||
.grammem
|
||||
.facts
|
||||
.contains(&mystem::Fact::Gender(Feminine))
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
true
|
||||
};
|
||||
let dialect = GenericDialect {};
|
||||
let ast: Vec<Statement> = match Parser::parse_sql(&dialect, &sql) {
|
||||
Ok(ast) => ast,
|
||||
Err(_) => {
|
||||
warn!("Invalid SQL - {}", sql);
|
||||
return Err(SQLInvalidCommand);
|
||||
}
|
||||
};
|
||||
match ast.len() {
|
||||
l if l > 1 => {
|
||||
return Err(Error::SQLBannedCommand(
|
||||
"🚫 One statement per message allowed 🚫".into(),
|
||||
))
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
match ast[0] {
|
||||
sqlparser::ast::Statement::Query { .. } => {}
|
||||
_ => {
|
||||
return Err(Error::SQLBannedCommand(
|
||||
"🚫 SELECT requests allowed only 🚫".into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
};
|
||||
let result = format!(
|
||||
"{} {} известн{} как {}, {}, а так же конечно {}. В прошедшем году ты часто давал{} нам знать, что ты {}, {} и {}. Не редко ты говорил{} я {}, я {} или даже я {}. =*",
|
||||
start.choose(&mut rand::thread_rng()).unwrap(),
|
||||
message.from.first_name.to_string(),
|
||||
{if fem {"ая"} else {"ый"}},
|
||||
nouns.pop().unwrap_or("=(".to_string()),
|
||||
nouns.pop().unwrap_or("=(".to_string()),
|
||||
nouns.pop().unwrap_or("=(".to_string()),
|
||||
{if fem {"а"} else {""}},
|
||||
verbs_p.pop().unwrap_or("=(".to_string()),
|
||||
verbs_p.pop().unwrap_or("=(".to_string()),
|
||||
verbs_p.pop().unwrap_or("=(".to_string()),
|
||||
{if fem {"а"} else {""}},
|
||||
verbs_i.pop().unwrap_or("=(".to_string()),
|
||||
verbs_i.pop().unwrap_or("=(".to_string()),
|
||||
verbs_i.pop().unwrap_or("=(".to_string()),
|
||||
|
||||
);
|
||||
debug!("{:?}", result);
|
||||
match api
|
||||
.send(
|
||||
message
|
||||
.text_reply(result.trim())
|
||||
.parse_mode(ParseMode::Html),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => debug!("/omedeto command sent to {}", message.chat.id()),
|
||||
Err(_) => warn!("/omedeto command sent failed to {}", message.chat.id()),
|
||||
let conn = db::open()?;
|
||||
let mut stmt = conn.prepare_cached(&sql)?;
|
||||
|
||||
let mut rows = match stmt.query(rusqlite::NO_PARAMS) {
|
||||
Err(e) => return Err(SQLITE3Error(e)),
|
||||
Ok(rows) => rows,
|
||||
};
|
||||
|
||||
let mut res: Vec<Vec<String>> = match rows.column_names() {
|
||||
Some(n) => vec![n
|
||||
.into_iter()
|
||||
.map(|s| {
|
||||
let t = String::from(s);
|
||||
if t.len() > 10 {
|
||||
"EMSGSIZE".to_string()
|
||||
} else {
|
||||
t
|
||||
}
|
||||
})
|
||||
.collect()],
|
||||
None => return Err(SQLInvalidCommand),
|
||||
};
|
||||
|
||||
let index_count = match rows.column_count() {
|
||||
Some(c) => c,
|
||||
None => return Err(SQLInvalidCommand),
|
||||
};
|
||||
while let Some(row) = rows.next().unwrap() {
|
||||
let mut tmp: Vec<String> = Vec::new();
|
||||
for i in 0..index_count {
|
||||
match row.get(i).unwrap_or(None) {
|
||||
Some(rusqlite::types::Value::Text(t)) => tmp.push(t),
|
||||
Some(rusqlite::types::Value::Integer(t)) => tmp.push(t.to_string()),
|
||||
Some(rusqlite::types::Value::Blob(_)) => tmp.push("Binary".to_string()),
|
||||
Some(rusqlite::types::Value::Real(t)) => tmp.push(t.to_string()),
|
||||
Some(rusqlite::types::Value::Null) => tmp.push("Null".to_string()),
|
||||
None => tmp.push("Null".to_string()),
|
||||
};
|
||||
}
|
||||
res.push(tmp);
|
||||
}
|
||||
if res.len() >= 100 {
|
||||
return Err(Error::SQLResultTooLong(
|
||||
"SQL result too long. Lines limit is 100. Use LIMIT".to_string(),
|
||||
));
|
||||
}
|
||||
// add Header
|
||||
let mut msg = if is_head {
|
||||
let mut x = String::from("<b>");
|
||||
for head in res[0].iter() {
|
||||
x = format!("{} {}", x, head);
|
||||
}
|
||||
format!("{}{}", x, "</b>\n")
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
// remove header
|
||||
res.remove(0);
|
||||
|
||||
msg = format!("{}{}", msg, "<pre>");
|
||||
for line in res.iter() {
|
||||
for field in line.iter() {
|
||||
msg = format!("{}{}", msg, format!("{} ", field));
|
||||
}
|
||||
msg = format!("{}{}", msg, "\n");
|
||||
}
|
||||
msg = format!("{}{}", msg, "</pre>");
|
||||
msg = if msg.len() > 4096 {
|
||||
"🚫 Result is too big. Use LIMIT 🚫".into()
|
||||
} else {
|
||||
msg
|
||||
};
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
// '^я [а-яА-Я]+(-[а-яА-Я]+(_[а-яА-Я]+)*)*$'
|
||||
Ok(())
|
||||
#[allow(unused_variables)]
|
||||
async fn exec_mystem(
|
||||
&self,
|
||||
api: &Api,
|
||||
message: &Message,
|
||||
mystem: &mut MyStem,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Execute for Here {
|
||||
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||
let members: Vec<telegram_bot::User> = db::get_members(message.chat.id()).unwrap();
|
||||
for u in &members {
|
||||
debug!("Found user {:?} in chat {}", u, message.chat.id());
|
||||
}
|
||||
let mut msg = "<b>I summon you</b>, ".to_string();
|
||||
for user in members {
|
||||
let mention = match user.username {
|
||||
Some(username) => format!("@{}", username),
|
||||
_ => format!(
|
||||
"<a href=\"tg://user?id={}\">{}</a>",
|
||||
encode_text(&user.id.to_string()),
|
||||
encode_text(&user.first_name)
|
||||
),
|
||||
};
|
||||
msg = format!("{} {}", msg, mention);
|
||||
}
|
||||
|
||||
match api
|
||||
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
||||
.await
|
||||
{
|
||||
Ok(_) => debug!("/here command sent to {}", message.chat.id()),
|
||||
Err(_) => warn!("/here command sent failed to {}", message.chat.id()),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
async fn exec_mystem(
|
||||
&self,
|
||||
api: &Api,
|
||||
message: &Message,
|
||||
mystem: &mut MyStem,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Execute for Top {
|
||||
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||
let top = db::get_top(&message).await?;
|
||||
let mut msg = "<b>Your top using words:</b>\n<pre>".to_string();
|
||||
let mut counter = 1;
|
||||
for word in top.iter() {
|
||||
msg = format!(
|
||||
"{} <b>{}</b> {} - {}\n",
|
||||
msg, counter, word.word, word.count
|
||||
);
|
||||
counter += 1;
|
||||
}
|
||||
msg = format!("{}{}", msg, "</pre>");
|
||||
match api
|
||||
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
||||
.await
|
||||
{
|
||||
Ok(_) => debug!("/top command sent to {}", message.chat.id()),
|
||||
Err(_) => warn!("/top command sent failed to {}", message.chat.id()),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
async fn exec_mystem(
|
||||
&self,
|
||||
api: &Api,
|
||||
message: &Message,
|
||||
mystem: &mut MyStem,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Execute for MarkovAll {
|
||||
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||
let messages = db::get_messages_random_all().await?;
|
||||
let mut chain = Chain::new();
|
||||
chain.feed(messages);
|
||||
let mut sentences = chain.generate();
|
||||
let mut msg = String::new();
|
||||
for _ in 1..rand::thread_rng().gen_range(2, 10) {
|
||||
msg = format!("{} {}", msg, sentences.pop().unwrap());
|
||||
}
|
||||
match api
|
||||
.send(message.text_reply(msg.trim()).parse_mode(ParseMode::Html))
|
||||
.await
|
||||
{
|
||||
Ok(_) => debug!("/markov_all command sent to {}", message.chat.id()),
|
||||
Err(_) => warn!("/markov_all command sent failed to {}", message.chat.id()),
|
||||
}
|
||||
//api.send(message.chat.text("Text to message chat")).await?;
|
||||
//api.send(message.from.text("Private text")).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
async fn exec_mystem(
|
||||
&self,
|
||||
api: &Api,
|
||||
message: &Message,
|
||||
mystem: &mut MyStem,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Execute for Markov {
|
||||
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||
let messages = db::get_messages_random_group(&message).await?;
|
||||
let mut chain = Chain::new();
|
||||
chain.feed(messages);
|
||||
let mut sentences = chain.generate();
|
||||
let mut msg = String::new();
|
||||
for _ in 1..rand::thread_rng().gen_range(2, 10) {
|
||||
msg = format!("{} {}", msg, sentences.pop().unwrap());
|
||||
}
|
||||
match api
|
||||
.send(message.text_reply(msg.trim()).parse_mode(ParseMode::Html))
|
||||
.await
|
||||
{
|
||||
Ok(_) => debug!("/markov command sent to {}", message.chat.id()),
|
||||
Err(_) => warn!("/markov command sent failed to {}", message.chat.id()),
|
||||
}
|
||||
//api.send(message.chat.text("Text to message chat")).await?;
|
||||
//api.send(message.from.text("Private text")).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
async fn exec_mystem(
|
||||
&self,
|
||||
api: &Api,
|
||||
message: &Message,
|
||||
mystem: &mut MyStem,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Execute for Omedeto {
|
||||
#[allow(unused_variables)]
|
||||
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[warn(unused_must_use)]
|
||||
async fn exec_mystem(
|
||||
&self,
|
||||
api: &Api,
|
||||
message: &Message,
|
||||
mystem: &mut MyStem,
|
||||
) -> Result<(), Error> {
|
||||
let all_msg = db::get_messages_user_all(&message).await?;
|
||||
let re = Regex::new(r"^[яЯ] [а-яА-Я]+(-[а-яА-Я]+(_[а-яА-Я]+)*)*").unwrap();
|
||||
let mut nouns: Vec<String> = all_msg
|
||||
.iter()
|
||||
.filter(|m| re.is_match(m))
|
||||
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||
.filter(|m| {
|
||||
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
||||
if !stem.is_empty() {
|
||||
if !stem[0].lex.is_empty() {
|
||||
match stem[0].lex[0].grammem.part_of_speech {
|
||||
mystem::PartOfSpeech::Noun => stem[0].lex[0]
|
||||
.grammem
|
||||
.facts
|
||||
.contains(&mystem::Fact::Case(Nominative)),
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.map(|w| w.replace(|z| z == '.' || z == ',', ""))
|
||||
.collect();
|
||||
nouns.sort();
|
||||
nouns.dedup();
|
||||
nouns.shuffle(&mut rand::thread_rng());
|
||||
//debug!("Found {} nouns. {:#?}", nouns.len(), nouns);
|
||||
|
||||
let mut verbs_p: Vec<String> = all_msg
|
||||
.iter()
|
||||
.filter(|m| re.is_match(m))
|
||||
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||
.filter(|m| {
|
||||
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
if stem.is_empty() {
|
||||
false
|
||||
} else if stem[0].lex.is_empty() {
|
||||
false
|
||||
} else {
|
||||
match stem[0].lex[0].grammem.part_of_speech {
|
||||
mystem::PartOfSpeech::Verb => stem[0].lex[0]
|
||||
.grammem
|
||||
.facts
|
||||
.contains(&mystem::Fact::Tense(Past)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
})
|
||||
.map(|w| w.replace(|z| z == '.' || z == ',', ""))
|
||||
.collect();
|
||||
verbs_p.sort();
|
||||
verbs_p.dedup();
|
||||
verbs_p.shuffle(&mut rand::thread_rng());
|
||||
//debug!("Found {} past verbs. {:#?}", verbs_p.len(), verbs_p);
|
||||
|
||||
let mut verbs_i: Vec<String> = all_msg
|
||||
.iter()
|
||||
.filter(|m| re.is_match(m))
|
||||
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||
.filter(|m| {
|
||||
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
if stem.is_empty() {
|
||||
false
|
||||
} else if stem[0].lex.is_empty() {
|
||||
false
|
||||
} else {
|
||||
match stem[0].lex[0].grammem.part_of_speech {
|
||||
mystem::PartOfSpeech::Verb => {
|
||||
stem[0].lex[0]
|
||||
.grammem
|
||||
.facts
|
||||
.contains(&mystem::Fact::Tense(Inpresent))
|
||||
&& stem[0].lex[0]
|
||||
.grammem
|
||||
.facts
|
||||
.contains(&mystem::Fact::Person(First))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
})
|
||||
.map(|w| w.replace(|z| z == '.' || z == ',', ""))
|
||||
.collect();
|
||||
verbs_i.sort();
|
||||
verbs_i.dedup();
|
||||
verbs_i.shuffle(&mut rand::thread_rng());
|
||||
//debug!("Found {} inpresent verbs. {:#?}", verbs_i.len(), verbs_i);
|
||||
|
||||
if nouns.is_empty() {
|
||||
nouns.push(message.from.first_name.to_string());
|
||||
}
|
||||
let start: Vec<String> = vec![
|
||||
"С новым годом".into(),
|
||||
"С НГ тебя".into(),
|
||||
"Поздравляю".into(),
|
||||
"Поздравляю с НГ".into(),
|
||||
];
|
||||
let placeholders: Vec<String> = vec![
|
||||
"[ДАННЫЕ УДАЛЕНЫ]".into(),
|
||||
"[СЕКРЕТНО]".into(),
|
||||
"[НЕТ ДАННЫХ]".into(),
|
||||
"[ОШИБКА ДОСТУПА]".into(),
|
||||
];
|
||||
//debug!("Nouns: {:#?}", nouns);
|
||||
//debug!("Verbs: {:#?}", verbs);
|
||||
|
||||
let fem = {
|
||||
let mut fm = 0;
|
||||
let mut mu = 0;
|
||||
all_msg
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter(|m| re.is_match(m))
|
||||
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||
.map(|m| {
|
||||
let stem = mystem.stemming(m).unwrap_or_default();
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
if stem.is_empty() {
|
||||
} else if stem[0].lex.is_empty() {
|
||||
} else {
|
||||
if let mystem::PartOfSpeech::Verb = stem[0].lex[0].grammem.part_of_speech {
|
||||
match stem[0].lex[0]
|
||||
.grammem
|
||||
.facts
|
||||
.contains(&mystem::Fact::Tense(Past))
|
||||
{
|
||||
true => {
|
||||
if stem[0].lex[0]
|
||||
.grammem
|
||||
.facts
|
||||
.contains(&mystem::Fact::Gender(Feminine))
|
||||
{
|
||||
fm += 1;
|
||||
} else {
|
||||
mu += 1;
|
||||
}
|
||||
}
|
||||
false => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.for_each(drop);
|
||||
//debug!("fm - {}, mu - {}", fm, mu);
|
||||
fm >= mu
|
||||
};
|
||||
//debug!("Is Feminine - {}", fem);
|
||||
let result = format!(
|
||||
"{} {} известн{} как {}, {}, а так же конечно {}. В прошедшем году ты часто давал{} нам знать, что ты {}, {} и {}. Нередко ты говорил{} я {}, я {} или даже я {}. =*",
|
||||
start.choose(&mut rand::thread_rng()).unwrap(),
|
||||
message.from.first_name.to_string(),
|
||||
{ if fem { "ая" } else { "ый" } },
|
||||
nouns.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||
nouns.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||
nouns.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||
{ if fem { "а" } else { "" } },
|
||||
verbs_p.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||
verbs_p.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||
verbs_p.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||
{ if fem { "а" } else { "" } },
|
||||
verbs_i.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||
verbs_i.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||
verbs_i.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||
);
|
||||
match api
|
||||
.send(
|
||||
message
|
||||
.text_reply(result.trim())
|
||||
.parse_mode(ParseMode::Html),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => debug!("/omedeto command sent to {}", message.chat.id()),
|
||||
Err(_) => warn!("/omedeto command sent failed to {}", message.chat.id()),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Execute for Code {
|
||||
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||
let mut lines: Vec<String> = self
|
||||
.data
|
||||
.trim()
|
||||
.split("\n")
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
if lines.len() >= 81 {
|
||||
return Err(CodeHighlightningError);
|
||||
}
|
||||
let last_line = &lines[lines.len() - 1];
|
||||
|
||||
let tags = last_line
|
||||
.trim()
|
||||
.split(|s| s == ' ' || s == '\n')
|
||||
.filter(|s| s.starts_with("#"))
|
||||
.map(|s| s.to_string().replace("#", ""))
|
||||
.map(|s| s.to_string().replace("_", " "))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let code = if tags.is_empty() {
|
||||
self.data.trim().to_string()
|
||||
} else {
|
||||
let _ = lines.pop();
|
||||
lines.join("\n")
|
||||
};
|
||||
if code.is_empty() {
|
||||
return Err(CodeHighlightningError);
|
||||
}
|
||||
let (ps, ts) = silicon::utils::init_syntect();
|
||||
let syntax: Vec<&SyntaxReference> = tags
|
||||
.iter()
|
||||
.map(|s| ps.find_syntax_by_token(s))
|
||||
.filter(|s| s.is_some())
|
||||
.map(|s| s.unwrap())
|
||||
.collect();
|
||||
let syntax = if syntax.len() != 1 {
|
||||
ps.find_syntax_by_token("js").unwrap()
|
||||
} else {
|
||||
syntax[0]
|
||||
};
|
||||
let theme: Vec<&Theme> = tags
|
||||
.iter()
|
||||
.map(|s| ts.themes.get(s))
|
||||
.filter(|s| s.is_some())
|
||||
.map(|s| s.unwrap())
|
||||
.collect();
|
||||
|
||||
let theme = if theme.len() != 1 {
|
||||
ts.themes.get("Dracula").unwrap()
|
||||
} else {
|
||||
theme[0]
|
||||
};
|
||||
|
||||
let mut h = HighlightLines::new(syntax, theme);
|
||||
let highlight = LinesWithEndings::from(&code)
|
||||
.map(|line| h.highlight(line, &ps))
|
||||
.collect::<Vec<_>>();
|
||||
let formatter = silicon::formatter::ImageFormatterBuilder::<String>::new()
|
||||
.window_controls(false)
|
||||
.line_offset(1)
|
||||
.round_corner(false);
|
||||
let mut formatter = formatter.build().unwrap();
|
||||
let image = formatter.format(&highlight, &theme);
|
||||
let path = "code.png";
|
||||
image
|
||||
.save(&path)
|
||||
.map_err(|e| error!("Failed to save image to {}: {}", path, e))
|
||||
.unwrap();
|
||||
|
||||
// let file = InputFileUpload::with_path("CODE.png");
|
||||
// api.send(message.chat.document(&file)).await?;
|
||||
//
|
||||
// // Send an image from disk
|
||||
// api.send( message.chat.photo(&file)).await?;
|
||||
//debug!("{:#?}", formatter);
|
||||
Ok(path.into())
|
||||
}
|
||||
|
||||
async fn exec_mystem(
|
||||
&self,
|
||||
api: &Api,
|
||||
message: &Message,
|
||||
mystem: &mut MyStem,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
33
src/db.rs
33
src/db.rs
@ -1,6 +1,5 @@
|
||||
use crate::errors;
|
||||
use crate::utils;
|
||||
use futures::StreamExt;
|
||||
use rusqlite::{named_params, params, Connection, Error, Result};
|
||||
use std::time::SystemTime;
|
||||
use telegram_bot::*;
|
||||
@ -55,7 +54,7 @@ pub(crate) fn get_user(id: telegram_bot::UserId) -> Result<telegram_bot::User, e
|
||||
})
|
||||
}
|
||||
|
||||
if users.len() == 0 {
|
||||
if users.is_empty() {
|
||||
Err(errors::Error::UserNotFound)
|
||||
} else {
|
||||
Ok(users[0].clone())
|
||||
@ -75,14 +74,14 @@ pub(crate) fn get_conf(id: telegram_bot::ChatId) -> Result<Conf, errors::Error>
|
||||
date: row.get(2)?,
|
||||
})
|
||||
}
|
||||
if confs.len() == 0 {
|
||||
if confs.is_empty() {
|
||||
Err(errors::Error::ConfNotFound)
|
||||
} else {
|
||||
Ok(confs[0].clone())
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn get_confs() -> Result<Vec<Conf>> {
|
||||
let conn = open()?;
|
||||
let mut stmt = conn.prepare("SELECT id, title, date FROM conf")?;
|
||||
@ -101,7 +100,7 @@ pub(crate) fn get_confs() -> Result<Vec<Conf>> {
|
||||
|
||||
Ok(confs)
|
||||
}
|
||||
*/
|
||||
|
||||
pub(crate) async fn get_messages_random_all() -> Result<Vec<String>, Error> {
|
||||
let conn = open()?;
|
||||
let mut stmt = conn.prepare_cached("SELECT text FROM messages ORDER BY RANDOM() LIMIT 50")?;
|
||||
@ -136,6 +135,7 @@ pub(crate) async fn get_messages_random_group(
|
||||
Ok(messages)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) async fn get_messages_user_group(
|
||||
message: &telegram_bot::Message,
|
||||
) -> Result<Vec<String>, Error> {
|
||||
@ -214,7 +214,7 @@ pub(crate) async fn add_conf(message: Message) -> Result<(), Error> {
|
||||
|
||||
match get_conf(message.chat.id()) {
|
||||
Ok(_) => {
|
||||
//info!("Group found: {:?}", message.chat.id());
|
||||
debug!("Group found: {:?}", message.chat.id());
|
||||
let update = Conf {
|
||||
id: message.chat.id(),
|
||||
title,
|
||||
@ -228,10 +228,10 @@ pub(crate) async fn add_conf(message: Message) -> Result<(), Error> {
|
||||
id = :id",
|
||||
)?;
|
||||
stmt.execute_named(&[(":id", &update.id.to_string()), (":title", &update.title)])?;
|
||||
//info!("Conf {:?} updated: {:?}", update.title, get_conf(update.id));
|
||||
debug!("Conf {:?} updated: {:?}", update.title, get_conf(update.id));
|
||||
}
|
||||
Err(_) => {
|
||||
//info!("Group didn't found: {:?}", message.chat.id());
|
||||
debug!("Group didn't found: {:?}", message.chat.id());
|
||||
|
||||
let update = Conf {
|
||||
id: message.chat.id(),
|
||||
@ -250,7 +250,7 @@ pub(crate) async fn add_conf(message: Message) -> Result<(), Error> {
|
||||
(":title", &update.title),
|
||||
(":date", &unix_time),
|
||||
])?;
|
||||
//info!("Conf {:?} added: {:?}", update.title, get_conf(update.id));
|
||||
debug!("Conf {:?} added: {:?}", update.title, get_conf(update.id));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@ -283,7 +283,7 @@ pub(crate) async fn add_user(message: Message) -> Result<(), Error> {
|
||||
(":first_name", &update.first_name),
|
||||
(":last_name", &update.last_name),
|
||||
])?;
|
||||
//println!("User {} updated: {:?}", update.first_name, get_user(user.id));
|
||||
debug!("User {} updated: {:?}", update.first_name, get_user(update.id));
|
||||
}
|
||||
Err(_) => {
|
||||
let unix_time = SystemTime::now()
|
||||
@ -310,7 +310,7 @@ pub(crate) async fn add_user(message: Message) -> Result<(), Error> {
|
||||
(":last_name", &user.last_name),
|
||||
(":date", &unix_time),
|
||||
])?;
|
||||
//println!("User added: {:?}", user);
|
||||
debug!("User added: {:?}", user);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@ -345,14 +345,12 @@ pub(crate) async fn get_file(file_id: String) -> Result<i64, errors::Error> {
|
||||
Ok(id) => Ok(id),
|
||||
Err(_) => Err(errors::Error::FileNotFound),
|
||||
};
|
||||
|
||||
file_rowid
|
||||
}
|
||||
|
||||
async fn add_word(word: &String) -> Result<i64, errors::Error> {
|
||||
match get_stop_word(&word).await {
|
||||
Err(_) => return Err(errors::Error::WordInStopList),
|
||||
_ => {}
|
||||
async fn add_word(word: &str) -> Result<i64, errors::Error> {
|
||||
if get_stop_word(&word).await.is_err() {
|
||||
return Err(errors::Error::WordInStopList);
|
||||
}
|
||||
let conn = open()?;
|
||||
let word_rowid =
|
||||
@ -366,7 +364,7 @@ async fn add_word(word: &String) -> Result<i64, errors::Error> {
|
||||
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()?;
|
||||
match conn.execute_named(
|
||||
"SELECT rowid FROM stop_words WHERE word = (:stop_word)",
|
||||
@ -400,6 +398,7 @@ async fn add_relation(word_id: i64, msg_id: i64, message: &Message) -> Result<i6
|
||||
Ok(rowid)
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
pub(crate) async fn add_sentence(
|
||||
message: &telegram_bot::Message,
|
||||
mystem: &mut mystem::MyStem,
|
||||
|
@ -20,51 +20,83 @@ pub enum Error {
|
||||
JsonParseError(serde_error),
|
||||
PopenError(popen_error),
|
||||
MystemError(mystem_error),
|
||||
SQLBannedCommand(String),
|
||||
SQLInvalidCommand,
|
||||
SQLResultTooLong(String),
|
||||
CodeHighlightningError,
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
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)
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sqlite_error> for Error {
|
||||
fn from(e: sqlite_error) -> Error {
|
||||
return Error::SQLITE3Error(e);
|
||||
Error::SQLITE3Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<tg_error> for Error {
|
||||
fn from(e: tg_error) -> Error {
|
||||
return Error::TelegramError(e);
|
||||
Error::TelegramError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<reqwest_error> for Error {
|
||||
fn from(e: reqwest_error) -> Error {
|
||||
return Error::ReqwestError(e);
|
||||
Error::ReqwestError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io_error> for Error {
|
||||
fn from(e: io_error) -> Error {
|
||||
return Error::IOError(e);
|
||||
Error::IOError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serde_error> for Error {
|
||||
fn from(e: serde_error) -> Error {
|
||||
return Error::JsonParseError(e);
|
||||
Error::JsonParseError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<popen_error> for Error {
|
||||
fn from(e: popen_error) -> Error {
|
||||
return Error::PopenError(e);
|
||||
Error::PopenError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<mystem_error> for Error {
|
||||
fn from(e: mystem_error) -> Error {
|
||||
return Error::MystemError(e);
|
||||
Error::MystemError(e)
|
||||
}
|
||||
}
|
||||
|
115
src/handlers.rs
115
src/handlers.rs
@ -1,10 +1,13 @@
|
||||
use crate::commands;
|
||||
//use crate::commands::Command;
|
||||
use crate::commands::{Code, Execute, Here, Markov, MarkovAll, Omedeto, Sql, Top};
|
||||
use crate::db;
|
||||
use crate::errors;
|
||||
use crate::utils;
|
||||
use mystem::MyStem;
|
||||
use telegram_bot::*;
|
||||
|
||||
include!("../assets/help_text.rs");
|
||||
|
||||
pub async fn handler(
|
||||
api: Api,
|
||||
message: Message,
|
||||
@ -21,17 +24,103 @@ pub async fn handler(
|
||||
title,
|
||||
&message.from.id,
|
||||
&message.from.first_name,
|
||||
data
|
||||
data.replace("\n", " ")
|
||||
);
|
||||
db::add_sentence(&message, mystem).await?;
|
||||
match data.as_str() {
|
||||
"/here" => commands::here(api, message).await?,
|
||||
"/top" => commands::top(api, message).await?,
|
||||
"/stat" => commands::top(api, message).await?,
|
||||
"/markov_all" => commands::markov_all(api, message).await?,
|
||||
"/markov" => commands::markov(api, message).await?,
|
||||
"/omedeto" => commands::omedeto(api, message, mystem).await?,
|
||||
_ => (),
|
||||
|
||||
let cleaned_message = data.replace(&format!("@{}", me.clone().username.unwrap()), "");
|
||||
match cleaned_message.as_str() {
|
||||
s if s.to_string().starts_with("/code") => {
|
||||
match {
|
||||
Code {
|
||||
data: s.replace("/code", ""),
|
||||
}
|
||||
.exec_with_result(&api, &message)
|
||||
.await
|
||||
} {
|
||||
Ok(path) => {
|
||||
let file = InputFileUpload::with_path(path.clone());
|
||||
// api.send(message.chat.document(&file)).await?;
|
||||
//
|
||||
// // Send an image from disk
|
||||
api.send(message.chat.photo(&file)).await?;
|
||||
//debug!("{:#?}", formatter);
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
Err(_) => {
|
||||
let _ = api
|
||||
.send(message.text_reply(CODE_HELP).parse_mode(ParseMode::Html))
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
s if s.contains("/here") => {
|
||||
db::add_sentence(&message, mystem).await?;
|
||||
Here {
|
||||
data: "".to_string(),
|
||||
}
|
||||
.exec(&api, &message)
|
||||
.await?
|
||||
}
|
||||
s if s.to_string().starts_with("/sql") => match {
|
||||
Sql {
|
||||
data: s.replace("/sql ", ""),
|
||||
}
|
||||
.exec_with_result(&api, &message)
|
||||
.await
|
||||
} {
|
||||
Ok(msg) => {
|
||||
let _ = api
|
||||
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
||||
.await?;
|
||||
}
|
||||
Err(e) => {
|
||||
let _ = api
|
||||
.send(
|
||||
message
|
||||
.text_reply(format!("Error: {:#?}", e))
|
||||
.parse_mode(ParseMode::Html),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
},
|
||||
"/top" => {
|
||||
Top {
|
||||
data: "".to_string(),
|
||||
}
|
||||
.exec(&api, &message)
|
||||
.await?
|
||||
}
|
||||
"/stat" => {
|
||||
Top {
|
||||
data: "".to_string(),
|
||||
}
|
||||
.exec(&api, &message)
|
||||
.await?
|
||||
}
|
||||
"/markov_all" => {
|
||||
MarkovAll {
|
||||
data: "".to_string(),
|
||||
}
|
||||
.exec(&api, &message)
|
||||
.await?
|
||||
}
|
||||
"/markov" => {
|
||||
Markov {
|
||||
data: "".to_string(),
|
||||
}
|
||||
.exec(&api, &message)
|
||||
.await?
|
||||
}
|
||||
"/omedeto" => {
|
||||
Omedeto {
|
||||
data: "".to_string(),
|
||||
}
|
||||
.exec_mystem(&api, &message, mystem)
|
||||
.await?
|
||||
}
|
||||
_ => {
|
||||
db::add_sentence(&message, mystem).await?
|
||||
}
|
||||
}
|
||||
}
|
||||
MessageKind::Photo { ref caption, .. } => {
|
||||
@ -42,7 +131,7 @@ pub async fn handler(
|
||||
title,
|
||||
&message.from.id,
|
||||
&message.from.first_name,
|
||||
caption.clone().unwrap_or("NO_TITLE".to_string())
|
||||
caption.clone().unwrap_or_else(|| "NO_TITLE".to_string())
|
||||
);
|
||||
utils::get_files(api, message, token).await?;
|
||||
}
|
||||
@ -55,7 +144,7 @@ pub async fn handler(
|
||||
title,
|
||||
&message.from.id,
|
||||
&message.from.first_name,
|
||||
caption.clone().unwrap_or("NO_TITLE".to_string())
|
||||
caption.clone().unwrap_or_else(|| "NO_TITLE".to_string())
|
||||
);
|
||||
utils::get_files(api, message, token).await?;
|
||||
}
|
||||
|
@ -49,7 +49,12 @@ async fn main() -> Result<(), errors::Error> {
|
||||
if let UpdateKind::Message(message) = update.kind {
|
||||
db::add_conf(message.clone()).await?;
|
||||
db::add_user(message.clone()).await?;
|
||||
handlers::handler(api.clone(), message, token.clone(), &mut mystem, me.clone()).await?;
|
||||
match handlers::handler(api.clone(), message, token.clone(), &mut mystem, me.clone())
|
||||
.await
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(e) => warn!("An error occurred handling command. {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -13,15 +13,14 @@ pub(crate) fn get_title(message: &Message) -> String {
|
||||
match &message.chat {
|
||||
MessageChat::Supergroup(chat) => chat.title.clone(),
|
||||
MessageChat::Group(chat) => chat.title.clone(),
|
||||
MessageChat::Private(_) => format!("PRIVATE"),
|
||||
MessageChat::Private(_) => "PRIVATE".to_string(),
|
||||
_ => "PRIVATE".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn create_dir(dir: &String) -> () {
|
||||
match fs_create_dir(dir) {
|
||||
Ok(_) => info!("Dir {} created.", dir),
|
||||
Err(_) => (),
|
||||
pub(crate) async fn create_dir(dir: &str) {
|
||||
if fs_create_dir(dir).is_ok() {
|
||||
info!("Dir {} created.", dir)
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user