Init commit

This commit is contained in:
House of vanity
2018-02-04 07:13:09 +03:00
committed by GitHub
parent 1444638e23
commit ea2be1f23f
9 changed files with 764 additions and 0 deletions

1
assets/cert.sh Normal file
View 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
View 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
View File

@ -0,0 +1,3 @@
[bot]
telegram_key = 530043167:AAHkasdasdGHvmNojcD2mUXUU_5z8lKs0
telegram_api = https://api.telegram.org/

423
assets/stop-word.ru Normal file
View File

@ -0,0 +1,423 @@
а
в
г
е
ж
и
к
м
о
с
т
у
я
бы
stat
вообще
/stat
во
вы
да
до
ее
ей
ею
её
же
за
из
им
их
ли
мы
на
не
ни
но
ну
нх
об
он
от
по
со
та
те
то
ту
ты
уж
без
был
вам
вас
ваш
вон
вот
все
всю
вся
всё
где
год
два
две
дел
для
его
ему
еще
ещё
или
ими
имя
как
кем
ком
кто
лет
мне
мог
мож
мои
мой
мор
моя
моё
над
нам
нас
наш
нее
ней
нем
нет
нею
неё
них
оба
она
они
оно
под
пор
при
про
раз
сам
сих
так
там
тем
тех
том
тот
тою
три
тут
уже
чем
что
эта
эти
это
эту
алло
буду
будь
бывь
была
были
было
быть
вами
ваша
ваше
ваши
ведь
весь
вниз
всем
всех
всею
года
году
даже
двух
день
если
есть
зато
кого
кому
куда
лишь
люди
мало
меля
меня
мимо
мира
мной
мною
мочь
надо
нами
наша
наше
наши
него
нему
ниже
ними
один
пока
пора
пять
рано
сама
сами
само
саму
свое
свои
свою
себе
себя
семь
стал
суть
твой
твоя
твоё
тебе
тебя
теми
того
тоже
тому
туда
хоть
хотя
чаще
чего
чему
чтоб
чуть
этим
этих
этой
этом
этот
более
будем
будет
будто
будут
вверх
вдали
вдруг
везде
внизу
время
всего
всеми
всему
всюду
давно
даром
долго
друго
занят
затем
зачем
здесь
иметь
какая
какой
когда
кроме
лучше
между
менее
много
могут
может
можно
можхо
назад
низко
нужно
одной
около
опять
очень
перед
позже
после
потом
почти
пятый
разве
рядом
самим
самих
самой
самом
своей
своих
сеаой
снова
собой
собою
такая
также
такие
такое
такой
тобой
тобою
тогда
тысяч
уметь
часто
через
чтобы
шесть
этими
этого
этому
близко
больше
будете
будешь
бывает
важная
важное
важные
важный
вокруг
восемь
всегда
второй
далеко
дальше
девять
десять
должно
другая
другие
других
другое
другой
занята
занято
заняты
значит
именно
иногда
каждая
каждое
каждые
каждый
кругом
меньше
начала
нельзя
нибудь
никуда
ничего
обычно
однако
одного
отсюда
первый
потому
почему
просто
против
раньше
самими
самого
самому
своего
сейчас
сказал
совсем
теперь
только
третий
хорошо
хотеть
хочешь
четыре
шестой
восьмой
впрочем
времени
говорил
говорит
девятый
десятый
кажется
конечно
которая
которой
которые
который
которых
наверху
наконец
недавно
немного
нередко
никогда
однажды
посреди
сегодня
седьмой
сказала
сказать
сколько
слишком
сначала
спасибо
двадцать
довольно
которого
наиболее
недалеко
особенно
отовсюду
двадцатый
миллионов
несколько
прекрасно
процентов
четвертый
двенадцать
непрерывно
пожалуйста
пятнадцать
семнадцать
тринадцать
двенадцатый
одиннадцать
пятнадцатый
семнадцатый
тринадцатый
шестнадцать
восемнадцать
девятнадцать
одиннадцатый
четырнадцать
шестнадцатый
восемнадцатый
девятнадцатый
действительно
четырнадцатый
многочисленная
многочисленное
многочисленные
многочисленный
ага

96
database.py Normal file
View 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
View 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
View 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
View 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
View 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