big update

This commit is contained in:
2019-03-04 02:23:12 +03:00
parent 5c0efb068b
commit f4c739a964
11 changed files with 296 additions and 104 deletions
Regular → Executable
+185 -55
View File
@@ -1,103 +1,233 @@
#!/usr/bin/env python3
import logging
from html import escape
from random import random
from queue import Queue, Empty
from time import sleep
from threading import Thread
import sentry_sdk
from telegram.error import Unauthorized, TelegramError
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
from telegram import Message, Update
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, CallbackQueryHandler
from telegram import Message, Update, Bot, InlineKeyboardMarkup, InlineKeyboardButton, User
import config
from models import Subscriber
queue = []
from config import BOT_TOKEN, SENTRY_DSN, MANAGEMENT_CHAT
from db import get_conn, Subscriber, PersistentMapping, commit
from send_users_list import send_users_list
def go_away(bot, update: Update):
# Subscriber(user_id=str(update.message.chat_id))
# update.message.reply_text('Вы были добавлены')
update.message.reply_text('Пожалуйста, обратитесь к @lono_contactbot')
logging.basicConfig(level=logging.WARNING)
queue = Queue()
sentry_sdk.init(dsn=SENTRY_DSN)
conn = get_conn()
MAX_MESSAGE_LENGTH = 4096
MAX_CAPTION_LENGTH = 1024
def unsubscribe(bot, update: Update):
Subscriber.deleteBy(user_id=str(update.message.chat_id))
update.message.reply_text('Вы были отписаны от бота. Обратитесь к @lono_contactbot за добавлением обратно.')
def _notify_access_request(bot: Bot, user: User):
markup = InlineKeyboardMarkup([[InlineKeyboardButton('Добавить', callback_data=f'add {user.id}')]])
bot.send_message(MANAGEMENT_CHAT, f'<a href="tg://user?id={user.id}">{escape(user.full_name)}</a> запросил доступ',
parse_mode='html', reply_markup=markup)
def msg(bot, update: Update):
queue.append(update.message)
def welcome(bot: Bot, update: Update):
if update.effective_user.id in conn.root.subscribers:
update.message.reply_text('Вы уже являетесь участником ЛОНО')
else:
update.message.reply_text('Пожалуйста, обратитесь к @lono_contactbot')
_notify_access_request(bot, update.message.from_user)
def task_queue(bot, job):
if not queue:
return
m = queue.pop(0)
current_chat = str(m.chat_id)
uids = set(s.user_id for s in Subscriber.select())
if current_chat not in uids:
return m.reply_text('Пожалуйста, обратитесь к @lono_contactbot')
# Subscriber(user_id=current_chat)
# m.reply_text('Вы были добавлены')
def unsubscribe(bot: Bot, update: Update):
del conn.root.subscribers[update.message.chat_id]
commit()
update.message.reply_text('Вы были отписаны от бота. '
'Обратитесь к @lono_contactbot если вы хотите подписаться снова.')
user = update.message.from_user
bot.send_message(MANAGEMENT_CHAT, f'<a href="tg://user?id={user.id}">{escape(user.full_name)}</a> отписался')
def add_user(bot: Bot, update: Update, groups=(), args=()):
if update.callback_query:
update.callback_query.answer()
if groups:
if update.callback_query.message.chat.id != MANAGEMENT_CHAT:
return
uid = groups[0]
elif args:
uid = args[0]
elif update.message and update.message.reply_to_message and update.message.reply_to_message.forward_from:
uid = update.message.reply_to_message.forward_from.id
else:
return bot.send_message(MANAGEMENT_CHAT, 'Укажите ID пользователя или ответьте на его сообщение')
try:
uids.remove(current_chat)
except KeyError:
uid = int(uid)
except (ValueError, TypeError):
pass
for uid in uids:
try:
user = conn.root.subscribers[uid] = Subscriber.from_chat(bot.get_chat(uid))
commit()
if update.callback_query:
update.callback_query.message.edit_reply_markup()
bot.send_message(MANAGEMENT_CHAT, f'<a href="tg://user?id={uid}">{escape(user.name)}</a> был добавлен',
parse_mode='html')
bot.send_message(uid, 'Добро пожаловать. Снова.')
except TelegramError as e:
bot.send_message(MANAGEMENT_CHAT, str(e))
def remove_user(bot: Bot, update: Update, groups=(), args=()):
if update.callback_query:
update.callback_query.answer()
if groups:
if update.callback_query.message.chat.id != MANAGEMENT_CHAT:
return
uid = groups[0]
elif args:
uid = args[0]
elif update.message and update.message.reply_to_message and update.message.reply_to_message.forward_from:
uid = update.message.reply_to_message.forward_from.id
else:
return bot.send_message(MANAGEMENT_CHAT, 'Укажите ID пользователя или ответьте на его сообщение')
try:
uid = int(uid)
except (ValueError, TypeError):
pass
try:
name = conn.root.subscribers[uid].name
del conn.root.subscribers[uid]
commit()
bot.send_message(MANAGEMENT_CHAT, f'<a href="tg://user?id={uid}">{escape(name)}</a> был удален',
parse_mode='html')
if update.callback_query:
update.callback_query.message.edit_reply_markup()
except KeyError:
bot.send_message(MANAGEMENT_CHAT, f'Пользователь id={uid} не был найден')
def users(bot: Bot, update: Update):
send_users_list()
def msg(bot: Bot, update: Update):
queue.put(update.message)
def _sign_text(text, m: Message, limit):
if not text:
text = ''
if text.startswith('!sign') or text.startswith('/sign'):
text = text[5:] + f'\n\n____________\n' \
f'by <a href="tg://user?id={m.from_user.id}">{escape(m.from_user.full_name)}</a>'
return text[:limit]
def _process_message(bot: Bot, m: Message):
current_chat = m.chat_id
users = conn.root.subscribers # type: PersistentMapping
if current_chat not in users:
_notify_access_request(bot, m.from_user)
return m.reply_text('Пожалуйста, обратитесь к @lono_contactbot')
text = _sign_text(m.text_html, m, MAX_MESSAGE_LENGTH)
caption = _sign_text(m.caption_html, m, MAX_CAPTION_LENGTH)
for uid, user in users.items():
if uid == current_chat:
continue
sleep(.02)
try:
if m.forward_from or m.forward_from_chat or m.forward_from_message_id or m.forward_signature:
m.forward(f'{uid}')
r = None
if m.forward_date:
r = m.forward(uid)
elif hasattr(m, 'audio') and m.audio:
a = m.audio
bot.send_audio(f'{uid}', a.file_id, a.duration, a.performer, a.title, m.caption_html, parse_mode='html')
r = bot.send_audio(uid, a.file_id, a.duration, a.performer, a.title, caption, parse_mode='html')
elif hasattr(m, 'document') and m.document:
d = m.document
bot.send_document(f'{uid}', d.file_id, d.file_name, m.caption_html, parse_mode='html')
r = bot.send_document(uid, d.file_id, d.file_name, caption, parse_mode='html')
elif hasattr(m, 'photo') and m.photo:
p = m.photo
bot.send_photo(f'{uid}', p[-1].file_id, m.caption_html, parse_mode='html')
r = bot.send_photo(uid, p[-1].file_id, caption, parse_mode='html')
elif hasattr(m, 'sticker') and m.sticker:
s = m.sticker
bot.send_sticker(f'{uid}', s.file_id)
r = bot.send_sticker(uid, s.file_id)
elif hasattr(m, 'video') and m.video:
v = m.video
bot.send_video(f'{uid}', v.file_id, v.duration, m.caption_html, parse_mode='html')
r = bot.send_video(uid, v.file_id, v.duration, caption, parse_mode='html')
elif hasattr(m, 'voice') and m.voice:
v = m.voice
bot.send_voice(f'{uid}', v.file_id, v.duration, m.caption_html, parse_mode='html')
r = bot.send_voice(uid, v.file_id, v.duration, caption, parse_mode='html')
elif hasattr(m, 'video_note') and m.video_note:
vn = m.video_note
bot.send_video_note(f'{uid}', vn.file_id, vn.duration, vn.length)
r = bot.send_video_note(uid, vn.file_id, vn.duration, vn.length)
elif hasattr(m, 'contact') and m.contact:
c = m.contact
bot.send_contact(f'{uid}', c.phone_number, c.first_name, c.last_name)
r = bot.send_contact(uid, c.phone_number, c.first_name, c.last_name)
elif hasattr(m, 'location') and m.location:
l = m.location
bot.send_location(f'{uid}', l.latitude, l.longitude)
r = bot.send_location(uid, l.latitude, l.longitude)
elif hasattr(m, 'venue') and m.venue:
v = m.venue
bot.send_venue(f'{uid}', v.location.latitude, v.location.longitude, v.title, v.address, v.foursquare_id)
l = v.location
r = bot.send_venue(uid, l.latitude, l.longitude, v.title, v.address, v.foursquare_id)
elif hasattr(m, 'text') and m.text:
txt = m.text_html
if txt.startswith('!sign') or txt.startswith('/sign'):
txt = txt[5:] + f'\n\n____________\n' \
f'by <a href="tg://user?id={m.from_user.id}">{escape(m.from_user.full_name)}</a>'
bot.send_message(f'{uid}', txt, 'html')
r = bot.send_message(uid, text, 'html')
if r:
user.update_from_message(r)
except Unauthorized:
Subscriber.deleteBy(user_id=uid)
name = conn.root.users[uid].name
del conn.root.users[uid]
commit()
bot.send_message(MANAGEMENT_CHAT, f'<a href="tg://user?id={uid}">{name}</a> был удален '
f'из-за блокировки бота')
except TelegramError:
sentry_sdk.capture_exception()
commit()
def task_queue(u: Updater):
while True:
if not u.running:
return
try:
m = queue.get(timeout=1) # type: Message
_process_message(u.bot, m)
except Empty:
pass
updater = Updater(config.BOT_TOKEN, workers=4)
updater.job_queue.run_repeating(task_queue, .04)
updater.dispatcher.add_handler(CommandHandler('start', go_away))
updater.dispatcher.add_handler(CommandHandler('stop', unsubscribe))
updater.dispatcher.add_handler(MessageHandler(Filters.all, msg))
except:
sentry_sdk.capture_exception()
if __name__ == '__main__':
updater = Updater(BOT_TOKEN, workers=4)
updater.dispatcher.add_handler(CommandHandler('start', welcome, Filters.private))
updater.dispatcher.add_handler(CommandHandler('stop', unsubscribe, Filters.private))
updater.dispatcher.add_handler(CommandHandler('add', add_user, Filters.chat(MANAGEMENT_CHAT)))
updater.dispatcher.add_handler(CallbackQueryHandler(add_user, pattern=r'^add (\d+)$', pass_groups=True))
updater.dispatcher.add_handler(CommandHandler('remove', remove_user, Filters.chat(MANAGEMENT_CHAT)))
updater.dispatcher.add_handler(CallbackQueryHandler(remove_user, pattern=r'^remove (\d+)$', pass_groups=True))
updater.dispatcher.add_handler(CommandHandler('users', users, Filters.chat(MANAGEMENT_CHAT)))
updater.dispatcher.add_handler(MessageHandler(Filters.private, msg))
updater.start_polling()
tq = Thread(target=task_queue, args=(updater,))
tq.start()
logging.warning('LONO has started')
updater.idle()
logging.warning('LONO is stopping...')
commit()
conn.close()