mirror of
https://github.com/house-of-vanity/conf_bot.git
synced 2025-07-06 14:24:08 +00:00
Init commit
This commit is contained in:
1
assets/cert.sh
Normal file
1
assets/cert.sh
Normal file
@ -0,0 +1 @@
|
||||
openssl req -newkey rsa:2048 -sha256 -nodes -keyout cert.key -x509 -days 365 -out cert.pem -subj /C=US/ST=New York/L=Brooklyn/O=Example Brooklyn Company/CN=hexor.ru
|
34
assets/main.db.sql
Normal file
34
assets/main.db.sql
Normal file
@ -0,0 +1,34 @@
|
||||
BEGIN TRANSACTION;
|
||||
-- DROP TABLE IF EXISTS `word`;
|
||||
CREATE TABLE IF NOT EXISTS `word` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`word` TEXT UNIQUE
|
||||
);
|
||||
-- DROP TABLE IF EXISTS `user`;
|
||||
CREATE TABLE IF NOT EXISTS `user` (
|
||||
`id` INTEGER NOT NULL UNIQUE,
|
||||
`username` TEXT NOT NULL,
|
||||
`first_name` INTEGER NOT NULL,
|
||||
`last_name` INTEGER NOT NULL,
|
||||
`date` INTEGER NOT NULL,
|
||||
PRIMARY KEY(`id`)
|
||||
);
|
||||
-- DROP TABLE IF EXISTS `relations`;
|
||||
CREATE TABLE IF NOT EXISTS `relations` (
|
||||
`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,
|
||||
FOREIGN KEY(`conf_id`) REFERENCES `conf`(`id`),
|
||||
FOREIGN KEY(`word_id`) REFERENCES `word`(`id`) ON DELETE CASCADE,
|
||||
FOREIGN KEY(`user_id`) REFERENCES `user`(`id`)
|
||||
);
|
||||
-- DROP TABLE IF EXISTS `conf`;
|
||||
CREATE TABLE IF NOT EXISTS `conf` (
|
||||
`id` NUMERIC NOT NULL UNIQUE,
|
||||
`title` TEXT,
|
||||
`date` INTEGER NOT NULL,
|
||||
PRIMARY KEY(`id`)
|
||||
);
|
||||
COMMIT;
|
3
assets/settings.ini
Normal file
3
assets/settings.ini
Normal file
@ -0,0 +1,3 @@
|
||||
[bot]
|
||||
telegram_key = 530043167:AAHkasdasdGHvmNojcD2mUXUU_5z8lKs0
|
||||
telegram_api = https://api.telegram.org/
|
423
assets/stop-word.ru
Normal file
423
assets/stop-word.ru
Normal file
@ -0,0 +1,423 @@
|
||||
а
|
||||
в
|
||||
г
|
||||
е
|
||||
ж
|
||||
и
|
||||
к
|
||||
м
|
||||
о
|
||||
с
|
||||
т
|
||||
у
|
||||
я
|
||||
бы
|
||||
stat
|
||||
вообще
|
||||
/stat
|
||||
во
|
||||
вы
|
||||
да
|
||||
до
|
||||
ее
|
||||
ей
|
||||
ею
|
||||
её
|
||||
же
|
||||
за
|
||||
из
|
||||
им
|
||||
их
|
||||
ли
|
||||
мы
|
||||
на
|
||||
не
|
||||
ни
|
||||
но
|
||||
ну
|
||||
нх
|
||||
об
|
||||
он
|
||||
от
|
||||
по
|
||||
со
|
||||
та
|
||||
те
|
||||
то
|
||||
ту
|
||||
ты
|
||||
уж
|
||||
без
|
||||
был
|
||||
вам
|
||||
вас
|
||||
ваш
|
||||
вон
|
||||
вот
|
||||
все
|
||||
всю
|
||||
вся
|
||||
всё
|
||||
где
|
||||
год
|
||||
два
|
||||
две
|
||||
дел
|
||||
для
|
||||
его
|
||||
ему
|
||||
еще
|
||||
ещё
|
||||
или
|
||||
ими
|
||||
имя
|
||||
как
|
||||
кем
|
||||
ком
|
||||
кто
|
||||
лет
|
||||
мне
|
||||
мог
|
||||
мож
|
||||
мои
|
||||
мой
|
||||
мор
|
||||
моя
|
||||
моё
|
||||
над
|
||||
нам
|
||||
нас
|
||||
наш
|
||||
нее
|
||||
ней
|
||||
нем
|
||||
нет
|
||||
нею
|
||||
неё
|
||||
них
|
||||
оба
|
||||
она
|
||||
они
|
||||
оно
|
||||
под
|
||||
пор
|
||||
при
|
||||
про
|
||||
раз
|
||||
сам
|
||||
сих
|
||||
так
|
||||
там
|
||||
тем
|
||||
тех
|
||||
том
|
||||
тот
|
||||
тою
|
||||
три
|
||||
тут
|
||||
уже
|
||||
чем
|
||||
что
|
||||
эта
|
||||
эти
|
||||
это
|
||||
эту
|
||||
алло
|
||||
буду
|
||||
будь
|
||||
бывь
|
||||
была
|
||||
были
|
||||
было
|
||||
быть
|
||||
вами
|
||||
ваша
|
||||
ваше
|
||||
ваши
|
||||
ведь
|
||||
весь
|
||||
вниз
|
||||
всем
|
||||
всех
|
||||
всею
|
||||
года
|
||||
году
|
||||
даже
|
||||
двух
|
||||
день
|
||||
если
|
||||
есть
|
||||
зато
|
||||
кого
|
||||
кому
|
||||
куда
|
||||
лишь
|
||||
люди
|
||||
мало
|
||||
меля
|
||||
меня
|
||||
мимо
|
||||
мира
|
||||
мной
|
||||
мною
|
||||
мочь
|
||||
надо
|
||||
нами
|
||||
наша
|
||||
наше
|
||||
наши
|
||||
него
|
||||
нему
|
||||
ниже
|
||||
ними
|
||||
один
|
||||
пока
|
||||
пора
|
||||
пять
|
||||
рано
|
||||
сама
|
||||
сами
|
||||
само
|
||||
саму
|
||||
свое
|
||||
свои
|
||||
свою
|
||||
себе
|
||||
себя
|
||||
семь
|
||||
стал
|
||||
суть
|
||||
твой
|
||||
твоя
|
||||
твоё
|
||||
тебе
|
||||
тебя
|
||||
теми
|
||||
того
|
||||
тоже
|
||||
тому
|
||||
туда
|
||||
хоть
|
||||
хотя
|
||||
чаще
|
||||
чего
|
||||
чему
|
||||
чтоб
|
||||
чуть
|
||||
этим
|
||||
этих
|
||||
этой
|
||||
этом
|
||||
этот
|
||||
более
|
||||
будем
|
||||
будет
|
||||
будто
|
||||
будут
|
||||
вверх
|
||||
вдали
|
||||
вдруг
|
||||
везде
|
||||
внизу
|
||||
время
|
||||
всего
|
||||
всеми
|
||||
всему
|
||||
всюду
|
||||
давно
|
||||
даром
|
||||
долго
|
||||
друго
|
||||
занят
|
||||
затем
|
||||
зачем
|
||||
здесь
|
||||
иметь
|
||||
какая
|
||||
какой
|
||||
когда
|
||||
кроме
|
||||
лучше
|
||||
между
|
||||
менее
|
||||
много
|
||||
могут
|
||||
может
|
||||
можно
|
||||
можхо
|
||||
назад
|
||||
низко
|
||||
нужно
|
||||
одной
|
||||
около
|
||||
опять
|
||||
очень
|
||||
перед
|
||||
позже
|
||||
после
|
||||
потом
|
||||
почти
|
||||
пятый
|
||||
разве
|
||||
рядом
|
||||
самим
|
||||
самих
|
||||
самой
|
||||
самом
|
||||
своей
|
||||
своих
|
||||
сеаой
|
||||
снова
|
||||
собой
|
||||
собою
|
||||
такая
|
||||
также
|
||||
такие
|
||||
такое
|
||||
такой
|
||||
тобой
|
||||
тобою
|
||||
тогда
|
||||
тысяч
|
||||
уметь
|
||||
часто
|
||||
через
|
||||
чтобы
|
||||
шесть
|
||||
этими
|
||||
этого
|
||||
этому
|
||||
близко
|
||||
больше
|
||||
будете
|
||||
будешь
|
||||
бывает
|
||||
важная
|
||||
важное
|
||||
важные
|
||||
важный
|
||||
вокруг
|
||||
восемь
|
||||
всегда
|
||||
второй
|
||||
далеко
|
||||
дальше
|
||||
девять
|
||||
десять
|
||||
должно
|
||||
другая
|
||||
другие
|
||||
других
|
||||
другое
|
||||
другой
|
||||
занята
|
||||
занято
|
||||
заняты
|
||||
значит
|
||||
именно
|
||||
иногда
|
||||
каждая
|
||||
каждое
|
||||
каждые
|
||||
каждый
|
||||
кругом
|
||||
меньше
|
||||
начала
|
||||
нельзя
|
||||
нибудь
|
||||
никуда
|
||||
ничего
|
||||
обычно
|
||||
однако
|
||||
одного
|
||||
отсюда
|
||||
первый
|
||||
потому
|
||||
почему
|
||||
просто
|
||||
против
|
||||
раньше
|
||||
самими
|
||||
самого
|
||||
самому
|
||||
своего
|
||||
сейчас
|
||||
сказал
|
||||
совсем
|
||||
теперь
|
||||
только
|
||||
третий
|
||||
хорошо
|
||||
хотеть
|
||||
хочешь
|
||||
четыре
|
||||
шестой
|
||||
восьмой
|
||||
впрочем
|
||||
времени
|
||||
говорил
|
||||
говорит
|
||||
девятый
|
||||
десятый
|
||||
кажется
|
||||
конечно
|
||||
которая
|
||||
которой
|
||||
которые
|
||||
который
|
||||
которых
|
||||
наверху
|
||||
наконец
|
||||
недавно
|
||||
немного
|
||||
нередко
|
||||
никогда
|
||||
однажды
|
||||
посреди
|
||||
сегодня
|
||||
седьмой
|
||||
сказала
|
||||
сказать
|
||||
сколько
|
||||
слишком
|
||||
сначала
|
||||
спасибо
|
||||
двадцать
|
||||
довольно
|
||||
которого
|
||||
наиболее
|
||||
недалеко
|
||||
особенно
|
||||
отовсюду
|
||||
двадцатый
|
||||
миллионов
|
||||
несколько
|
||||
прекрасно
|
||||
процентов
|
||||
четвертый
|
||||
двенадцать
|
||||
непрерывно
|
||||
пожалуйста
|
||||
пятнадцать
|
||||
семнадцать
|
||||
тринадцать
|
||||
двенадцатый
|
||||
одиннадцать
|
||||
пятнадцатый
|
||||
семнадцатый
|
||||
тринадцатый
|
||||
шестнадцать
|
||||
восемнадцать
|
||||
девятнадцать
|
||||
одиннадцатый
|
||||
четырнадцать
|
||||
шестнадцатый
|
||||
восемнадцатый
|
||||
девятнадцатый
|
||||
действительно
|
||||
четырнадцатый
|
||||
многочисленная
|
||||
многочисленное
|
||||
многочисленные
|
||||
многочисленный
|
||||
ага
|
96
database.py
Normal file
96
database.py
Normal file
@ -0,0 +1,96 @@
|
||||
import datetime as dt
|
||||
|
||||
class DataBase:
|
||||
def __init__(self, basefile, scheme):
|
||||
import sqlite3
|
||||
try:
|
||||
self.conn = sqlite3.connect(basefile, check_same_thread=False)
|
||||
except:
|
||||
print('Could not connect to DataBase.')
|
||||
return None
|
||||
with open(scheme, 'r') as scheme_sql:
|
||||
sql = scheme_sql.read()
|
||||
if self.conn is not None:
|
||||
try:
|
||||
cursor = self.conn.cursor()
|
||||
cursor.executescript(sql)
|
||||
except:
|
||||
print('Could not create scheme.')
|
||||
else:
|
||||
print("Error! cannot create the database connection.")
|
||||
print('DB created.')
|
||||
|
||||
def execute(self, sql):
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute(sql)
|
||||
self.conn.commit()
|
||||
return cursor.fetchall()
|
||||
|
||||
def save_word(self, word):
|
||||
sql = "INSERT OR IGNORE INTO word('word') VALUES ('%s')" % word
|
||||
self.execute(sql)
|
||||
sql = "SELECT id FROM word WHERE word = '%s'" % word
|
||||
return(self.execute(sql)[0][0])
|
||||
|
||||
def add_user(self,
|
||||
username,
|
||||
user_id,
|
||||
first_name,
|
||||
last_name):
|
||||
date = int(dt.datetime.now().strftime("%s"))
|
||||
sql = """INSERT OR IGNORE INTO
|
||||
user('id', 'username', 'first_name', 'last_name', 'date')
|
||||
VALUES ('%s','%s','%s','%s','%s')""" % (
|
||||
user_id,
|
||||
username,
|
||||
first_name,
|
||||
last_name,
|
||||
date
|
||||
)
|
||||
self.execute(sql)
|
||||
|
||||
def add_conf(self, id, title):
|
||||
date = int(dt.datetime.now().strftime("%s"))
|
||||
sql = """INSERT OR IGNORE INTO
|
||||
conf('id', 'title', 'date')
|
||||
VALUES ('%s','%s','%s')""" % (
|
||||
id,
|
||||
title,
|
||||
date
|
||||
)
|
||||
self.execute(sql)
|
||||
|
||||
def add_relation(self, word, user_id, conf_id):
|
||||
word_id = self.save_word(word)
|
||||
date = int(dt.datetime.now().strftime("%s"))
|
||||
sql = """INSERT OR IGNORE INTO
|
||||
relations('word_id', 'user_id', 'conf_id', 'date')
|
||||
VALUES ('%s','%s','%s','%s')""" % (
|
||||
word_id,
|
||||
user_id,
|
||||
conf_id,
|
||||
date
|
||||
)
|
||||
self.execute(sql)
|
||||
|
||||
def get_top(self, user_id, conf_id, limit=10):
|
||||
sql= """
|
||||
SELECT w.word, COUNT(*) as count FROM relations r
|
||||
LEFT JOIN word w ON w.id = r.word_id
|
||||
LEFT JOIN `user` u ON u.id = r.user_id
|
||||
WHERE u.id = '%s' AND
|
||||
r.conf_id = '%s'
|
||||
GROUP BY w.word
|
||||
ORDER BY count DESC
|
||||
LIMIT %s
|
||||
""" % (
|
||||
user_id,
|
||||
conf_id,
|
||||
limit
|
||||
)
|
||||
result = self.execute(sql)
|
||||
return(result)
|
||||
|
||||
|
||||
def close(self):
|
||||
self.conn.close()
|
20
main.py
Normal file
20
main.py
Normal file
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from webhook import WebHook
|
||||
import settings
|
||||
import signal
|
||||
import sys
|
||||
|
||||
# catch ctrl+c
|
||||
def signal_handler(signal, frame):
|
||||
print('Exiting...')
|
||||
settings.db.close()
|
||||
sys.exit(0)
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
wh = WebHook(
|
||||
certfile = 'assets/cert.pem',
|
||||
keyfile='assets/cert.key',
|
||||
port=8080)
|
||||
|
||||
wh.serve()
|
15
settings.py
Normal file
15
settings.py
Normal file
@ -0,0 +1,15 @@
|
||||
from worker import MessageWorker
|
||||
from database import DataBase
|
||||
from configparser import ConfigParser
|
||||
|
||||
global parser
|
||||
parser = ConfigParser()
|
||||
parser.read('assets/settings.ini')
|
||||
|
||||
global db
|
||||
db = DataBase(
|
||||
basefile='main.db',
|
||||
scheme='assets/main.db.sql')
|
||||
|
||||
global worker
|
||||
worker = MessageWorker(db = db)
|
65
webhook.py
Normal file
65
webhook.py
Normal file
@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from http.server import HTTPServer,SimpleHTTPRequestHandler,CGIHTTPRequestHandler
|
||||
from socketserver import BaseServer
|
||||
import ssl
|
||||
import json
|
||||
import settings
|
||||
|
||||
# fuckin dirty hack. idk the best way to inherit return func into
|
||||
# RequestHandler class
|
||||
|
||||
class RequestHandler(SimpleHTTPRequestHandler):
|
||||
def __init__(self,
|
||||
request,
|
||||
client_address,
|
||||
server):
|
||||
self.worker = settings.worker
|
||||
super(RequestHandler, self).__init__(
|
||||
request=request,
|
||||
client_address=client_address,
|
||||
server=server)
|
||||
|
||||
def do_POST(self):
|
||||
"""Serve a POST request."""
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', 'text/html')
|
||||
self.end_headers()
|
||||
|
||||
length = self.headers.get('content-length')
|
||||
post_body = self.rfile.read(int(length))
|
||||
msg = json.loads(post_body.decode("utf-8"))
|
||||
msg2 = post_body.decode("utf-8")
|
||||
fh = open("log.json","a+")
|
||||
fh.write(msg2)
|
||||
fh.close()
|
||||
self.worker.handleUpdate(msg)
|
||||
|
||||
def do_GET(self):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class WebHook:
|
||||
def __init__(self,
|
||||
certfile,
|
||||
keyfile,
|
||||
address = '0.0.0.0',
|
||||
port=8443,
|
||||
RequestHandler=RequestHandler):
|
||||
|
||||
self.httpd = HTTPServer((address, port), RequestHandler)
|
||||
self.httpd.socket = ssl.wrap_socket (self.httpd.socket,
|
||||
certfile=certfile,
|
||||
keyfile=keyfile,
|
||||
server_side=True)
|
||||
|
||||
def serve(self):
|
||||
try:
|
||||
self.httpd.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
# Clean-up server (close socket, etc.)
|
||||
self.httpd.server_close()
|
107
worker.py
Normal file
107
worker.py
Normal file
@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from string import punctuation
|
||||
import subprocess
|
||||
from database import DataBase
|
||||
import os
|
||||
import urllib.request
|
||||
from urllib.parse import urlencode
|
||||
import settings
|
||||
|
||||
class MessageWorker:
|
||||
def __init__(self, db, stop_words = 'assets/stop-word.ru'):
|
||||
self.stop_words = stop_words
|
||||
self.db = db
|
||||
|
||||
def handleUpdate(self, msg):
|
||||
try:
|
||||
if msg['message']['text'] == '/stat':
|
||||
conf_id = msg['message']['chat']['id']
|
||||
user_id = msg['message']['from']['id']
|
||||
chat_title = msg['message']['chat']['title']
|
||||
self.db.add_conf(conf_id, chat_title)
|
||||
|
||||
message = """Here is your top:\n"""
|
||||
top = self.db.get_top(
|
||||
user_id=user_id,
|
||||
conf_id=conf_id
|
||||
)
|
||||
for word in top:
|
||||
message += '*%s*: %s\n' % (word[1], word[0])
|
||||
self.send(id=conf_id, msg=message)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
try:
|
||||
text = msg['message']['text']
|
||||
username = msg['message']['from']['username']
|
||||
try:
|
||||
last_name = msg['message']['from']['last_name']
|
||||
except:
|
||||
last_name = '_null'
|
||||
try:
|
||||
first_name = msg['message']['from']['first_name']
|
||||
except:
|
||||
first_name = '_null'
|
||||
user_id = msg['message']['from']['id']
|
||||
chat_id = msg['message']['chat']['id']
|
||||
chat_title = msg['message']['chat']['title']
|
||||
#print(self.clean_text(text))
|
||||
except:
|
||||
return False
|
||||
|
||||
collection = self.clean_text(text)
|
||||
|
||||
self.db.add_user(username,
|
||||
user_id,
|
||||
first_name,
|
||||
last_name)
|
||||
|
||||
self.db.add_conf(chat_id, chat_title)
|
||||
|
||||
for word in collection:
|
||||
self.db.add_relation(word=word, user_id=user_id, conf_id=chat_id)
|
||||
|
||||
|
||||
def clean_text(self, s):
|
||||
file = open(self.stop_words, 'rt')
|
||||
sw = file.read().split('\n')
|
||||
file.close()
|
||||
# dirty hack with dat fucking file
|
||||
fh = open("tmp.txt","w")
|
||||
fh.write(s)
|
||||
fh.close()
|
||||
cmd = "./assets/mystem -nlwd < tmp.txt"
|
||||
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
|
||||
output = ps.communicate()[0]
|
||||
os.remove("tmp.txt")
|
||||
# end of the fuckin' dirty hack
|
||||
s = output.decode('utf8')
|
||||
s = s.replace('?', '')
|
||||
s = s.split('\n')
|
||||
collection = []
|
||||
for word in s:
|
||||
if len(word) >2:
|
||||
if word not in sw:
|
||||
collection.append(word)
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
return collection
|
||||
|
||||
def send(self, id, msg):
|
||||
url = settings.parser.get('bot', 'telegram_api') + \
|
||||
'bot'+ settings.parser.get('bot', 'telegram_key') \
|
||||
+ '/sendMessage'
|
||||
post_fields = {
|
||||
'text': msg,
|
||||
'chat_id': id,
|
||||
'parse_mode': 'Markdown',
|
||||
'disable_web_page_preview': 1
|
||||
}
|
||||
urllib.request.Request(url, urlencode(post_fields).encode())
|
||||
request = urllib.request.Request(url, urlencode(post_fields).encode())
|
||||
json = urllib.request.urlopen(request).read().decode()
|
||||
return json
|
Reference in New Issue
Block a user