async def send_bot_response(self, user: str, response: BotResponse): if response.message: images = response.images disable_unicode = not self.bot.get_user_setting( user, BotUserSettings.FORMATTING) max_chars = 2000 if response.choices: max_chars = 640 messages = split_message(adapt_text(str(response), just_strip=disable_unicode), max_chars=max_chars) for i in range(0, len(messages)): buttons = None if response.choices and i == len(messages) - 1: buttons = [] if len(response.choices) > 3: response.choices = response.choices[:3] for choice in response.choices: buttons.append( PostbackButton(choice.label, choice.callback_data)) await self.fb_messenger.send_message(user, messages[i], images=images, buttons=buttons) images = None SENT_MESSAGE_COUNT.inc()
async def handle_messenger_msg(self, message: Message): RECV_MESSAGE_COUNT.inc() try: user_input = message.text if message.payload: user_input = message.payload responses = self.bot.handle_input(user_input, message.sender_id) for response in responses: await self.send_bot_response(message.sender_id, response) except Exception as e: self.log.exception( "An error happened while handling a FB Messenger message", exc_info=e) self.log.exception( f"Message from {message.sender_id}: {message.text}") self.log.exception("Exiting!") await self.fb_messenger.send_reply( message, adapt_text(self.bot.get_error_message().message)) try: tb_list = traceback.format_exception(None, e, e.__traceback__) tb_string = ''.join(tb_list) await self.sendMessageToDev( f"An exception occurred: {tb_string}\n" f"Message from {message.sender_id}: {message.text}") except Exception: self.log.error(f"Could not send message to developers") # Just exit on exception os.kill(os.getpid(), signal.SIGINT)
async def send_message_to_users(self, message: str, users: List[Union[str, int]]): if not users: users = map(lambda x: x.platform_id, self.bot.get_all_users()) message = UserHintService.format_commands(message, self.bot.command_formatter) for user in users: await TextMessage(self.connection, text=adapt_text(message, True), to_id=user).send() self.log.warning(f"Sent message to {user}")
async def send_message_to_users(self, message: str, users: List[Union[str, int]]): if not users: users = map(lambda x: x.platform_id, self.bot.get_all_users()) message = UserHintService.format_commands(message, self.bot.command_formatter) for user in users: disable_unicode = not self.bot.get_user_setting( user, BotUserSettings.FORMATTING) await self.fb_messenger.send_message( user, adapt_text(message, just_strip=disable_unicode)) self.log.warning(f"Sent message to {user}")
async def handle_threema_msg(self, message: Message): if type(message) == TextMessage: RECV_MESSAGE_COUNT.inc() message: TextMessage try: responses = self.bot.handle_input(message.text, message.from_id) for response in responses: await self.send_bot_response(message.from_id, response) except Exception as e: self.log.exception( "An error happened while handling a Threema message", exc_info=e) self.log.exception( f"Message from {message.from_id}: {message.text}") self.log.exception("Exiting!") try: response_msg = TextMessage( self.connection, text=adapt_text(self.bot.get_error_message().message, True), to_id=message.from_id) await response_msg.send() except Exception: self.log.error( f"Could not send message to {message.from_id}") try: tb_list = traceback.format_exception( None, e, e.__traceback__) tb_string = ''.join(tb_list) await self.sendMessageToDev( f"An exception occurred: {tb_string}\n" f"Message from {message.from_id}: {message.text}") except Exception: self.log.error(f"Could not send message to developers") # Just exit on exception os.kill(os.getpid(), signal.SIGINT) elif type(message) == DeliveryReceipt: pass else: self.log.warning( f"Received unknown message type {type(message)}: {message}")
async def send_bot_response(self, user: str, response: BotResponse): if response.images: for image in response.images: response_img = ImageMessage(self.connection, image_path=image, to_id=user) await response_img.send() SENT_IMAGES_COUNT.inc() if response.message: message_parts = split_message(adapt_text(str(response), threema_format=True), max_bytes=3500) for m in message_parts: response_msg = TextMessage(self.connection, text=m, to_id=user) await response_msg.send() SENT_MESSAGE_COUNT.inc()
async def send_message_to_users(self, message: str, users: List[str]) -> None: """ Send a message to specific or all users Args: message: Message to send users: List of user ids or None for all signal users """ if not users: users = map(lambda x: x.platform_id, self.bot.get_all_users()) message = UserHintService.format_commands(message, self.bot.command_formatter) async with semaphore.Bot(self.phone_number, socket_path=self.socket, profile_name=self.profile_name, profile_picture=self.profile_picture, raise_errors=True) as bot: for user in users: disable_unicode = not self.bot.get_user_setting(user, BotUserSettings.FORMATTING) await bot.send_message(user, adapt_text(str(message), just_strip=disable_unicode))
def update(self) -> bool: last_update = self.get_last_update() if last_update and datetime.now() - last_update < timedelta(hours=12): return False new_data = False response = self.get_resource(self.URL) if response: self.log.debug("Got RulesGermany Data") data = json.loads(response) updated = datetime.now() with self.connection.cursor() as cursor: from covidbot.utils import adapt_text for bl in data: district_id = self.get_district_id(bl['Bundesland']) if not district_id: self.log.warning(f"Could not get ID of {bl['Bundesland']}") continue text = bl['Überblick'] text = adapt_text(text, just_strip=True) link = f'https://tourismus-wegweiser.de/detail/?bl={bl["Kürzel"]}' cursor.execute("SELECT text, link FROM district_rules WHERE district_id=%s", [district_id]) row = cursor.fetchone() if row: if row[0] == text and row[1] == link: continue cursor.execute("UPDATE district_rules SET text=%s, link=%s, updated=%s WHERE district_id=%s", [text, link, updated, district_id]) else: cursor.execute("INSERT INTO district_rules (district_id, text, link, updated) " "VALUES (%s, %s, %s, %s)", [district_id, text, link, updated]) new_data = True self.connection.commit() return new_data
async def send_response(self, room_id: str, responses: List[BotResponse]): # Check if device is verified # if self.matrix.room_contains_unverified(room.room_id): # devices = self.matrix.room_devices(room.room_id) # for user in devices: # for device in devices[user]: # self.matrix.verify_device(devices[user][device]) # self.log.debug(f"Verified {device} of {user}") if self.debug: return for message in responses: if message.images: for image in message.images: # Calculate metadata mime_type = "image/jpeg" file_stat = os.stat(image) im = Image.open(image) (width, height) = im.size url = await self.upload_file(image, mime_type) image = { "body": os.path.basename(image), "msgtype": "m.image", "url": url, "info": { "size": file_stat.st_size, "mimetype": mime_type, "w": width, # width in pixel "h": height, # height in pixel }, } resp = await self.matrix.room_send( room_id=room_id, message_type="m.room.message", content=image, ignore_unverified_devices=True) if isinstance(resp, ErrorResponse): self.log.error(f"Could not send image: {resp}") else: SENT_IMAGES_COUNT.inc() resp = await self.matrix.room_send(room_id=room_id, message_type="m.room.message", content={ "msgtype": "m.text", "body": adapt_text(str(message), just_strip=True), "format": "org.matrix.custom.html", "formatted_body": str(message).replace( "\n", "<br />") }, ignore_unverified_devices=True) if isinstance(resp, ErrorResponse): self.log.error(f"Could not send message: {resp}") FAILED_MESSAGE_COUNT.inc() else: SENT_MESSAGE_COUNT.inc()
def format_response(bot_response: BotResponse, just_strip: bool): bot_response.message = adapt_text(str(bot_response), just_strip=just_strip) return bot_response
async def send_to_dev(self, message: str, bot: semaphore.Bot): await bot.send_message(self.dev_chat, adapt_text(message))
async def send_unconfirmed_reports(self) -> None: """ Send unconfirmed daily reports to the specific users """ if not self.bot.user_messages_available(): return async with semaphore.Bot(self.phone_number, socket_path=self.socket, profile_name=self.profile_name, profile_picture=self.profile_picture, raise_errors=True) as bot: backoff_time = random.uniform(2, 6) message_counter = 0 for report_type, userid, message in self.bot.get_available_user_messages(): self.log.info(f"Try to send report {message_counter}") disable_unicode = not self.bot.get_user_setting(userid, BotUserSettings.FORMATTING) for elem in message: success = False rate_limited = False try: success = await bot.send_message(userid, adapt_text(elem.message, just_strip=disable_unicode), attachments=elem.images) except InternalError as e: if "org.whispersystems.signalservice.api.push.exceptions.RateLimitException" in e.exceptions: rate_limited = True break elif "org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException" in e.exceptions \ or "org.whispersystems.signalservice.api.push.exceptions.NotFoundException" in e.exceptions: self.log.warning( f"Account does not exist anymore, delete it: {userid}") self.bot.delete_user(userid) break elif "org.whispersystems.signalservice.api.push.exceptions.ProofRequiredException" in e.exceptions: self.log.warning(f"ProofRequired for {userid}") break else: raise e except RateLimitError as e: self.log.error(f"Invalid Send Request: {e.message}") rate_limited = True break except NoSuchAccountError as e: self.log.warning( f"Account does not exist anymore, delete it: {e.account}") self.bot.delete_user(userid) break except UnknownGroupError: self.log.warning( f"Group does not exist anymore, delete it: {userid}") self.bot.delete_user(userid) break except (NoSendPermissionError, InvalidRecipientError) as e: self.log.warning( f"We cant send to {userid}, disabling user: {e.message}") self.bot.disable_user(userid) break except UnknownError as e: self.log.error(f"Unknown Signald Error {e.error_type}: {e.error}") raise e except SignaldError as e: self.log.error(f"Unknown Signald Error {e}") raise e if success: self.log.warning(f"({message_counter}) Sent daily report to {userid}") self.bot.confirm_message_send(report_type, userid) else: self.log.error( f"({message_counter}) Error sending daily report to {userid}") backoff_time = self.backoff_timer(backoff_time, rate_limited) message_counter += 1
async def sendMessageToDev(self, message: str): await TextMessage(self.connection, text=adapt_text(message, True), to_id=self.dev_chat).send()