import yaml from pytgbot.bot.synchronous import SyncBot from pytgbot.api_types.sendable.inline import ( InlineQueryResultArticle, InputTextMessageContent, ) from pytgbot.api_types.receivable.inline import InlineQuery from pytgbot.api_types.receivable.updates import Update from .states import CreatePostWorkflow from urllib.parse import urljoin # from . import solr,reindex from solrfet2020 import SolrFet2020 from . import fet, users from .users import User from io import BytesIO from key import API_KEY import requests from .workflows import AuthWorkflow import logging logger = logging.getLogger() from misc import SaveFileMapping, SaveFileObject #from lxml.html.clean import clean_html, Cleaner import settings solr = SolrFet2020() def TelegramIntegrationException(Exception): pass def get_chat_id(update): if update.message and update.message.chat: return update.message.chat.id if update.callback_query: return update.callback_query.message.chat.id def get_message_id(update): if update.message: return update.message.message_id def get_from_id(update): if update.message and update.message.to_array(): return str(update.message.to_array()["from"]["id"]) if update.callback_query and update.callback_query.to_array(): return str(update.callback_query.to_array()["from"]["id"]) def get_from(update): if update.message and update.message.to_array(): return update.message.to_array()["from"] if update.callback_query and update.callback_query.to_array(): return update.callback_query.to_array()["from"] def download_file(url): local_filename = url.split("/")[-1] # NOTE the stream=True parameter below with requests.get(url, stream=True) as r: r.raise_for_status() with open(local_filename, "wb") as f: for chunk in r.iter_content(chunk_size=8192): # If you have chunk encoded response uncomment if # and set chunk_size parameter to None. # if chunk: f.write(chunk) return local_filename class BaseChat(SaveFileObject): "Basis für einen Telegram Chat" def __init__(self, id, bot): self.id = id # self.chat_id=chat_id self.bot = bot self.workflows = {} self.last_message_id = None self.debug = False self.type = "group" self.mode = "" def to_dict(self): return { "id": self.id, "workflows": self.workflows, "debug": self.debug, "type": self.type, "mode": self.mode, } @classmethod def from_dict(self, bot, d): c = Chat(d["id"], bot) c.debug = d["debug"] c.type = d["type"] c.mode = d.get("mode", "") return c def echo(self, update): self.reply_msg(yaml.dump(update._raw) + "\nfrom" + str(get_from_id(update))) def send_msg(self, text, **kwargs): self.bot.send_message(chat_id=self.id, text=text, **kwargs) def reply_msg(self, text, **kwargs): self.bot.send_message( chat_id=self.id, text=text, reply_to_message_id=self.last_message_id, **kwargs ) def asdict(self): return self.to_dict() def inline(self, query): pass def log_update(self, update): with open("chat_logs/%s.yaml" % self.id, "a+") as f: f.write(yaml.safe_dump([update.to_array()])) def process_update(self, update): self.log_update(update) if update.inline_query: return self.inline(update.inline_query) self.last_message_id = get_message_id(update) w = self.workflows.get(get_from_id(update), None) if w: self.workflows[get_from_id(update)] = w if w and w.is_finished: self.workflows[get_from_id(update)] = None w = None if self.debug: self.echo(update) if update.message and w: w.process_message(update.message.text) if update.callback_query: self.send_msg("processing callback %s" % str(w)) if w: w.process_message(update.callback_query.data) self.bot.edit_message_text( chat_id=update.callback_query.message.chat.id, message_id=update.callback_query.message.message_id, text=update.callback_query.message.text + ": " + update.callback_query.data, ) if update.message and update.message.photo: ff = max( update.message.photo, key=lambda x: x.file_size ) # Foto mit bester Auflösung fff = self.bot.get_file(ff.file_id) url = fff.get_download_url(API_KEY) r = requests.get(url) fn = url.split("/")[-1] media = (fn, BytesIO(r.content), r.headers["content-type"]) if w: w.process_message(update.message.text, media=media) if update.message and update.message.chat: self.type = update.message.chat.type u = users[update] users.to_file() class Chat(BaseChat): def inline(self, query): # r=solr.search("text_txt: %s" % ,sort="date_dt desc").docs links, hits = solr.search(query.query) r = links[0:6] res = [ InlineQueryResultArticle( id=d["url"][0:49], title=d["title"], url=urljoin(settings.TARGET, d["url"]), thumb_url=urljoin(settings.TARGET, d["image"]), input_message_content=InputTextMessageContent( message_text=urljoin(settings.TARGET, d["url"]) ), ) for d in r[0:10] ] self.bot.answer_inline_query(inline_query_id=query.id, results=res) return def process_command(self, cmd, txt, update): self.last_message_id = get_message_id(update) u = users[update] # users[get_from_id(update)]=u if cmd == "/s" or cmd == "/search": self.reply_msg("searching ...") links, hits = solr.search(txt) for d in links: self.send_msg(str(d["text"]), parse_mode="html") if hits == 0: self.send_msg("Nichts gefunden sorry.") return True elif cmd == "/mode": self.mode = txt self.reply_msg("Mode: %s" % txt) return True elif cmd == "/debug": if not u.fet_user: self.reply_msg( "bitte vorher /auth ausführen wenn du ein FET Mitglied bist" ) return True if self.debug: self.debug = False else: self.debug = True # not self.debug self.reply_msg("Debug: %s" % str(self.debug)) return True elif cmd == "/post": if not u.fet_user: self.reply_msg( "bitte vorher /auth ausführen wenn du ein FET Mitglied bist" ) return True self.workflows[get_from_id(update)] = CreatePostWorkflow(chat=self) return True elif cmd == "/reindex": if not u.fet_user: self.reply_msg( "bitte vorher /auth ausführen wenn du ein FET Mitglied bist" ) return True self.reply_msg("Das kann ein bissl dauern...") solr.reindex() self.send_msg("Fertig mit dem neuen Index") return True elif cmd == "/reindextest": if not u.fet_user: self.reply_msg( "bitte vorher /auth ausführen wenn du ein FET Mitglied bist" ) return True self.reply_msg("Das kann ein bissl dauern...") solr.reindextest() self.send_msg("Fertig mit dem neuen Index") return True elif cmd == "/auth": if u.fet_user: self.reply_msg("Du bist schon authentifiziert...") else: u.token = "afwerve" u.a = 1 self.reply_msg( urljoin("https://" + settings.URL_HOSTNAME, "/auth/%s/%s" % (u.id, u.token)) ) self.send_msg(urljoin("https://", settings.URL_HOSTNAME)) users.to_file() return True else: return False return False def get_command_from_update(update): "get the command and the text if there is one" if ( update.message and update.message.entities and update.message.entities[0].type == "bot_command" ): return ( update.message.text[ update.message.entities[0].offset : update.message.entities[0].offset + update.message.entities[0].length ], update.message.text[ update.message.entities[0].offset + update.message.entities[0].length : ].strip(), ) return None, None class ChatManager(SaveFileMapping): def __init__(self, bot): super().__init__(file=settings.CHATFILE) if not type(bot) is SyncBot: raise TelegramIntegrationException( "This ChatManager needs a SyncBot from pytgbot as an argument" ) self.bot = bot self.from_file() def __getitem__(self, key): if type(key) is Update: return self.__getitem__(get_chat_id(key)) c = super().__getitem__(key) if not c: c = Chat(id=key, bot=self.bot) self[key] = c return c def from_dict(self, dd): if type(dd) is dict: self.data = {dd[d]["id"]: Chat.from_dict(self.bot, dd[d]) for d in dd} elif dd is not None: raise AttributeError("from_dict needs a dict got %s" % str(type(dd))) def send(self, chat_id=None, text=None): if int(chat_id) in self.chats: self.chats[int(chat_id)].send_msg(text) else: logger.debug(yaml.dump(self.chats)) def process_update(self, update): chat = self[update] cmd, txt = get_command_from_update(update) if cmd: if not chat.process_command(cmd, txt, update): chat.reply_msg("Wrong command %s" % cmd) else: chat.process_update(update) self.to_file()