def get_message_by_id(self, chat: Chat, msg_id: MessageID) -> Optional['Message']: index = None if msg_id.split('.')[-1].isdecimal(): # is sub-message index = int(msg_id.split('.')[-1]) msg_id = MessageID('.'.join(msg_id.split('.')[:-1])) thread_id, thread_type = self.client._getThread(chat.uid, None) message_info = self.client._forcedFetch(thread_id, msg_id).get("message") message = Message._from_graphql(message_info) efb_msg = self.client.build_efb_msg(msg_id, chat.uid, message.author, message) attachments = message_info.get('delta', {}).get('attachments', []) if attachments: attachment = attachments[index] self.client.attach_media(efb_msg, attachment) efb_msg.uid = msg_id return efb_msg
def wrap_func(self: 'SlaveMessageManager', msg: wxpy.Message, *args, **kwargs): logger = logging.getLogger(__name__) logger.debug("[%s] Raw message: %r", msg.id, msg.raw) efb_msg: Optional[Message] = func(self, msg, *args, **kwargs) if efb_msg is None: return if getattr(coordinator, 'master', None) is None: logger.debug("[%s] Dropping message as master channel is not ready yet.", efb_msg.uid) return efb_msg.deliver_to = coordinator.master # Format message IDs as JSON of List[List[str]]. efb_msg.uid = MessageID(json.dumps( [[str(getattr(msg, "id", constants.INVALID_MESSAGE_ID + str(uuid.uuid4())))]] )) if not efb_msg.chat or not efb_msg.author: chat, author = self.get_chat_and_author(msg) # Do not override what's defined in the wrapped methods efb_msg.chat = efb_msg.chat or chat efb_msg.author = efb_msg.author or author logger.debug("[%s] Chat: %s, Author: %s", efb_msg.uid, efb_msg.chat, efb_msg.author) coordinator.send_message(efb_msg) if efb_msg.file: efb_msg.file.close()
def make_chat_head(self, update: Update, context: CallbackContext) -> int: """ Create a chat head. Triggered by callback message with status `Flags.CHAT_HEAD_CONFIRM`. This message is a part of the ``/chat`` conversation handler. """ tg_chat_id = update.effective_chat.id tg_msg_id = update.effective_message.message_id callback_uid: str = update.callback_query.data # Refresh with a new set of pages if callback_uid.split()[0] == "offset": update.callback_query.answer() return self.chat_head_req_generate(tg_chat_id, message_id=tg_msg_id, offset=int( callback_uid.split()[1])) if callback_uid == Flags.CANCEL_PROCESS: txt = self._("Cancelled.") self.msg_storage.pop((tg_chat_id, tg_msg_id), None) self.bot.edit_message_text(text=txt, chat_id=tg_chat_id, message_id=tg_msg_id) update.callback_query.answer() return ConversationHandler.END if not callback_uid.startswith("chat "): # Invalid command txt = self._("Invalid command. ({0})").format(callback_uid) self.msg_storage.pop((tg_chat_id, tg_msg_id), None) self.bot.edit_message_text(text=txt, chat_id=tg_chat_id, message_id=tg_msg_id) update.callback_query.answer() return ConversationHandler.END callback_idx = int(callback_uid.split()[1]) chat: ETMChatType = self.msg_storage[(tg_chat_id, tg_msg_id)].chats[callback_idx] chat_display_name = chat.full_name self.msg_storage.pop((tg_chat_id, tg_msg_id), None) txt = self._("Reply to this message to chat with {0}.").format( chat_display_name) chat_head_etm = ETMMsg() chat_head_etm.chat = chat chat_head_etm.author = chat.self or chat.add_self() chat_head_etm.uid = MessageID("__chathead__") chat_head_etm.type = MsgType.Text chat_head_etm.text = txt chat_head_etm.type_telegram = TGMsgType.Text chat_head_etm.deliver_to = self.channel self.db.add_or_update_message_log(chat_head_etm, update.effective_message) self.bot.edit_message_text(text=txt, chat_id=tg_chat_id, message_id=tg_msg_id) update.callback_query.answer() return ConversationHandler.END
def send_message(self, msg: Message) -> Message: if msg.type == MsgType.Text: coordinator.send_message(Message( uid=MessageID(f'echo_{uuid4()}'), type=MsgType.Text, chat=self.chat, author=self.chat.other, deliver_to=coordinator.master, text=msg.text, )) return msg
def wechat_system_msg(self, msg: wxpy.Message) -> Optional[Message]: if msg.recalled_message_id: recall_id = str(msg.recalled_message_id) # check conversion table first if recall_id in self.recall_msg_id_conversion: # prevent feedback of messages deleted by master channel. del self.recall_msg_id_conversion[recall_id] return None # val = self.recall_msg_id_conversion.pop(recall_id) # val[1] -= 1 # if val[1] > 0: # not all associated messages are recalled. # return None # else: # efb_msg.uid = val[0] else: # Format message IDs as JSON of List[List[str]]. chat, author = self.get_chat_and_author(msg) efb_msg = Message( chat=chat, author=author, uid=MessageID(json.dumps([[recall_id]])) ) coordinator.send_status(MessageRemoval(source_channel=self.channel, destination_channel=coordinator.master, message=efb_msg)) return None chat, _ = self.get_chat_and_author(msg) try: author = chat.get_member(SystemChatMember.SYSTEM_ID) except KeyError: author = chat.add_system_member() if any(i in msg.text for i in self.NEW_CHAT_PATTERNS): coordinator.send_status(ChatUpdates( channel=self.channel, new_chats=(chat.uid,) )) elif any(i in msg.text for i in self.CHAT_AND_MEMBER_UPDATE_PATTERNS): # TODO: detect actual member changes from message text coordinator.send_status(ChatUpdates( channel=self.channel, modified_chats=(chat.uid,) )) return Message( text=msg.text, type=MsgType.Text, chat=chat, author=author, )
def on_message(self, mid: str = '', author_id: str = '', message: str = '', message_object: Message = None, thread_id: str = '', thread_type: str = ThreadType.USER, ts: str = '', metadata=None, msg=None): """ Called when the client is listening, and somebody sends a message Args: mid: The message ID author_id: The ID of the author message: (deprecated. Use `message_object.text` instead) message_object (models.Message): The message (As a `Message` object) thread_id: Thread ID that the message was sent to. See :ref:`intro_threads` thread_type (models.ThreadType): Type of thread that the message was sent to. See :ref:`intro_threads` ts: The timestamp of the message metadata: Extra metadata about the message msg: A full set of the data received """ # Ignore messages sent by EFMS time.sleep(0.25) if mid in self.sent_messages: self.sent_messages.remove(mid) return self.logger.debug("[%s] Received message from Messenger: %s", mid, message_object) efb_msg = self.build_efb_msg(mid, thread_id, author_id, message_object) attachments = msg.get('attachments', []) if len(attachments) > 1: self.logger.debug("[%s] Multiple attachments detected. Splitting into %s messages.", mid, len(attachments)) self.message_mappings[mid] = len(attachments) for idx, i in enumerate(attachments): sub_msg = copy.copy(efb_msg) sub_msg.uid = MessageID(f"{efb_msg.uid}.{idx}") self.attach_media(sub_msg, i) coordinator.send_message(sub_msg) return if attachments: self.attach_media(efb_msg, attachments[0]) coordinator.send_message(efb_msg) self.markAsDelivered(mid, thread_id)
def build_efb_msg(self, mid: str, thread_id: str, author_id: str, message_object: Message, nested: bool = False) -> EFBMessage: efb_msg = EFBMessage( uid=MessageID(mid), text=message_object.text, type=MsgType.Text, deliver_to=coordinator.master, ) # Authors efb_msg.chat = self.chat_manager.get_thread(thread_id) efb_msg.author = efb_msg.chat.get_member(ChatID(author_id)) if not nested and message_object.replied_to: efb_msg.target = self.build_efb_msg(message_object.reply_to_id, thread_id=thread_id, author_id=message_object.author, message_object=message_object.replied_to, nested=True) if message_object.mentions: mentions: Dict[Tuple[int, int], ChatMember] = dict() for i in message_object.mentions: mentions[(i.offset, i.offset + i.length)] = efb_msg.chat.get_member(i.thread_id) efb_msg.substitutions = Substitutions(mentions) if message_object.emoji_size: efb_msg.text += " (%s)" % message_object.emoji_size.name[0] # " (S)", " (M)", " (L)" if message_object.reactions: reactions: DefaultDict[ReactionName, List[ChatMember]] = defaultdict(list) for user_id, reaction in message_object.reactions.items(): reactions[ReactionName(reaction.value)].append( efb_msg.chat.get_member(user_id)) efb_msg.reactions = reactions return efb_msg
def process_telegram_message(self, update: Update, context: CallbackContext, destination: EFBChannelChatIDStr, quote: bool = False): """ Process messages came from Telegram. Args: update: Telegram message update context: PTB update context destination: Destination of the message specified. quote: If the message shall quote another one """ # Message ID for logging message_id = utils.message_id_to_str(update=update) message: Message = update.effective_message edited = bool(update.edited_message or update.edited_channel_post) self.logger.debug('[%s] Message is edited: %s, %s', message_id, edited, message.edit_date) channel, uid, gid = utils.chat_id_str_to_id(destination) if channel not in coordinator.slaves: return self.bot.reply_error( update, self._("Internal error: Slave channel “{0}” not found."). format(channel)) m = ETMMsg() log_message = True try: m.uid = MessageID(message_id) # Store Telegram message type m.type_telegram = mtype = get_msg_type(message) if self.TYPE_DICT.get(mtype, None): m.type = self.TYPE_DICT[mtype] self.logger.debug("[%s] EFB message type: %s", message_id, mtype) else: self.logger.info( "[%s] Message type %s is not supported by ETM", message_id, mtype) raise EFBMessageTypeNotSupported( self. _("{type_name} messages are not supported by EFB Telegram Master channel." ).format(type_name=mtype.name)) m.put_telegram_file(message) # Chat and author related stuff m.chat = self.chat_manager.get_chat(channel, uid, build_dummy=True) m.author = m.chat.self or m.chat.add_self() m.deliver_to = coordinator.slaves[channel] if quote: self.attach_target_message(message, m, channel) # Type specific stuff self.logger.debug("[%s] Message type from Telegram: %s", message_id, mtype) if m.type not in coordinator.slaves[ channel].supported_message_types: self.logger.info( "[%s] Message type %s is not supported by channel %s", message_id, m.type.name, channel) raise EFBMessageTypeNotSupported( self. _("{type_name} messages are not supported by slave channel {channel_name}." ).format(type_name=m.type.name, channel_name=coordinator.slaves[channel]. channel_name)) # Parse message text and caption to markdown msg_md_text = message.text and message.text_markdown if msg_md_text and msg_md_text == escape_markdown(message.text): msg_md_text = message.text msg_md_text = msg_md_text or "" msg_md_caption = message.caption and message.caption_markdown if msg_md_caption and msg_md_caption == escape_markdown( message.caption): msg_md_caption = message.caption msg_md_caption = msg_md_caption or "" # Flag for edited message if edited: m.edit = True text = msg_md_text or msg_md_caption msg_log = self.db.get_msg_log( master_msg_id=utils.message_id_to_str(update=update)) if not msg_log or msg_log.slave_message_id == self.db.FAIL_FLAG: raise EFBMessageNotFound() m.uid = msg_log.slave_message_id if text.startswith(self.DELETE_FLAG): coordinator.send_status( MessageRemoval( source_channel=self.channel, destination_channel=coordinator.slaves[channel], message=m)) if not self.channel.flag('prevent_message_removal'): try: message.delete() except telegram.TelegramError: message.reply_text( self._("Message is removed in remote chat.")) else: message.reply_text( self._("Message is removed in remote chat.")) log_message = False return self.logger.debug('[%s] Message is edited (%s)', m.uid, m.edit) if m.file_unique_id and m.file_unique_id != msg_log.file_unique_id: self.logger.debug( "[%s] Message media is edited (%s -> %s)", m.uid, msg_log.file_unique_id, m.file_unique_id) m.edit_media = True # Enclose message as an Message object by message type. if mtype is TGMsgType.Text: m.text = msg_md_text elif mtype is TGMsgType.Photo: m.text = msg_md_caption m.mime = "image/jpeg" self._check_file_download(message.photo[-1]) elif mtype in (TGMsgType.Sticker, TGMsgType.AnimatedSticker): # Convert WebP to the more common PNG m.text = "" self._check_file_download(message.sticker) elif mtype is TGMsgType.Animation: m.text = msg_md_caption self.logger.debug( "[%s] Telegram message is a \"Telegram GIF\".", message_id) m.filename = getattr(message.document, "file_name", None) or None if m.filename and not m.filename.lower().endswith(".gif"): m.filename += ".gif" m.mime = message.document.mime_type or m.mime elif mtype is TGMsgType.Document: m.text = msg_md_caption self.logger.debug("[%s] Telegram message type is document.", message_id) m.filename = getattr(message.document, "file_name", None) or None m.mime = message.document.mime_type self._check_file_download(message.document) elif mtype is TGMsgType.Video: m.text = msg_md_caption m.mime = message.video.mime_type self._check_file_download(message.video) elif mtype is TGMsgType.VideoNote: m.text = msg_md_caption self._check_file_download(message.video) elif mtype is TGMsgType.Audio: m.text = "%s - %s\n%s" % (message.audio.title, message.audio.performer, msg_md_caption) m.mime = message.audio.mime_type self._check_file_download(message.audio) elif mtype is TGMsgType.Voice: m.text = msg_md_caption m.mime = message.voice.mime_type self._check_file_download(message.voice) elif mtype is TGMsgType.Location: # TRANSLATORS: Message body text for location messages. m.text = self._("Location") m.attributes = LocationAttribute(message.location.latitude, message.location.longitude) elif mtype is TGMsgType.Venue: m.text = f"📍 {message.location.title}\n{message.location.adderss}" m.attributes = LocationAttribute( message.venue.location.latitude, message.venue.location.longitude) elif mtype is TGMsgType.Contact: contact: telegram.Contact = message.contact m.text = self._( "Shared a contact: {first_name} {last_name}\n{phone_number}" ).format(first_name=contact.first_name, last_name=contact.last_name, phone_number=contact.phone_number) elif mtype is TGMsgType.Dice: # Per docs, message.dice must be one of [1, 2, 3, 4, 5, 6], # DICE_CHAR is of length 7, so should be safe. m.text = f"{self.DICE_CHAR[message.dice.value]} ({message.dice.value})" else: raise EFBMessageTypeNotSupported( self._("Message type {0} is not supported.").format( mtype.name)) slave_msg = coordinator.send_message(m) if slave_msg and slave_msg.uid: m.uid = slave_msg.uid else: m.uid = None except EFBChatNotFound as e: self.bot.reply_error(update, e.args[0] or self._("Chat is not found.")) except EFBMessageTypeNotSupported as e: self.bot.reply_error( update, e.args[0] or self._("Message type is not supported.")) except EFBOperationNotSupported as e: self.bot.reply_error( update, self._("Message editing is not supported.\n\n{exception!s}". format(exception=e))) except EFBException as e: self.bot.reply_error( update, self._("Message is not sent.\n\n{exception!s}".format( exception=e))) self.logger.exception( "Message is not sent. (update: %s, exception: %s)", update, e) except Exception as e: self.bot.reply_error( update, self._("Message is not sent.\n\n{exception!r}".format( exception=e))) self.logger.exception( "Message is not sent. (update: %s, exception: %s)", update, e) finally: if log_message: self.db.add_or_update_message_log(m, update.effective_message) if m.file: m.file.close()
def generate_message_uid(messages: List[wxpy.SentMessage]) -> MessageID: return MessageID( json.dumps([[message.chat.puid, message.id, message.local_id] for message in messages]))
def process_telegram_message( self, update: Update, context: CallbackContext, channel_id: Optional[ModuleID] = None, chat_id: Optional[ChatID] = None, target_msg: Optional[utils.TgChatMsgIDStr] = None): """ Process messages came from Telegram. Args: update: Telegram message update context: PTB update context channel_id: Slave channel ID if specified chat_id: Slave chat ID if specified target_msg: Target slave message if specified """ target: Optional[EFBChannelChatIDStr] = None target_channel: Optional[ModuleID] = None target_log: Optional['MsgLog'] = None # Message ID for logging message_id = utils.message_id_to_str(update=update) multi_slaves: bool = False destination: Optional[EFBChannelChatIDStr] = None slave_msg: Optional[EFBMsg] = None message: telegram.Message = update.effective_message edited = bool(update.edited_message or update.edited_channel_post) self.logger.debug('[%s] Message is edited: %s, %s', message_id, edited, message.edit_date) private_chat = update.effective_chat.type == telegram.Chat.PRIVATE if not private_chat: # from group linked_chats = self.db.get_chat_assoc( master_uid=utils.chat_id_to_str(self.channel_id, update.effective_chat.id)) if len(linked_chats) == 1: destination = linked_chats[0] elif len(linked_chats) > 1: multi_slaves = True reply_to = bool(getattr(message, "reply_to_message", None)) # Process predefined target (slave) chat. cached_dest = self.chat_dest_cache.get(message.chat.id) if channel_id and chat_id: destination = utils.chat_id_to_str(channel_id, chat_id) if target_msg is not None: target_log = self.db.get_msg_log(master_msg_id=target_msg) if target_log: target = target_log.slave_origin_uid if target is not None: target_channel, target_uid = utils.chat_id_str_to_id( target) else: return self.bot.reply_error( update, self._("Message is not found in database. " "Please try with another message. (UC07)")) elif private_chat: if reply_to: dest_msg = self.db.get_msg_log( master_msg_id=utils.message_id_to_str( message.reply_to_message.chat.id, message.reply_to_message.message_id)) if dest_msg: destination = dest_msg.slave_origin_uid self.chat_dest_cache.set(message.chat.id, dest_msg.slave_origin_uid) else: return self.bot.reply_error( update, self._("Message is not found in database. " "Please try with another one. (UC03)")) elif cached_dest: destination = cached_dest self._send_cached_chat_warning(update, message.chat.id, cached_dest) else: return self.bot.reply_error( update, self._("Please reply to an incoming message. (UC04)")) else: # group chat if multi_slaves: if reply_to: dest_msg = self.db.get_msg_log( master_msg_id=utils.message_id_to_str( message.reply_to_message.chat.id, message.reply_to_message.message_id)) if dest_msg: destination = dest_msg.slave_origin_uid assert destination is not None self.chat_dest_cache.set(message.chat.id, destination) else: return self.bot.reply_error( update, self._("Message is not found in database. " "Please try with another one. (UC05)")) elif cached_dest: destination = cached_dest self._send_cached_chat_warning(update, message.chat.id, cached_dest) else: return self.bot.reply_error( update, self. _("This group is linked to multiple remote chats. " "Please reply to an incoming message. " "To unlink all remote chats, please send /unlink_all . (UC06)" )) elif destination: if reply_to: target_log = \ self.db.get_msg_log(master_msg_id=utils.message_id_to_str( message.reply_to_message.chat.id, message.reply_to_message.message_id)) if target_log: target = target_log.slave_origin_uid if target is not None: target_channel, target_uid = utils.chat_id_str_to_id( target) else: return self.bot.reply_error( update, self._("Message is not found in database. " "Please try with another message. (UC07)")) else: return self.bot.reply_error( update, self._("This group is not linked to any chat. (UC06)")) self.logger.debug( "[%s] Telegram received. From private chat: %s; Group has multiple linked chats: %s; " "Message replied to another message: %s", message_id, private_chat, multi_slaves, reply_to) self.logger.debug("[%s] Destination chat = %s", message_id, destination) assert destination is not None channel, uid = utils.chat_id_str_to_id(destination) if channel not in coordinator.slaves: return self.bot.reply_error( update, self._("Internal error: Channel \"{0}\" not found.").format( channel)) m = ETMMsg() log_message = True try: m.uid = MessageID(message_id) m.put_telegram_file(message) mtype = m.type_telegram # Chat and author related stuff m.author = ETMChat(db=self.db, channel=self.channel).self() m.chat = ETMChat(db=self.db, channel=coordinator.slaves[channel]) m.chat.chat_uid = m.chat.chat_name = uid # TODO: get chat from ETM local cache when available chat_info = self.db.get_slave_chat_info(channel, uid) if chat_info: m.chat.chat_name = chat_info.slave_chat_name m.chat.chat_alias = chat_info.slave_chat_alias m.chat.chat_type = ChatType(chat_info.slave_chat_type) m.deliver_to = coordinator.slaves[channel] if target and target_log is not None and target_channel == channel: if target_log.pickle: trgt_msg: ETMMsg = ETMMsg.unpickle(target_log.pickle, self.db) trgt_msg.target = None else: trgt_msg = ETMMsg() trgt_msg.type = MsgType.Text trgt_msg.text = target_log.text trgt_msg.uid = target_log.slave_message_id trgt_msg.chat = ETMChat( db=self.db, channel=coordinator.slaves[target_channel]) trgt_msg.chat.chat_name = target_log.slave_origin_display_name trgt_msg.chat.chat_alias = target_log.slave_origin_display_name trgt_msg.chat.chat_uid = utils.chat_id_str_to_id( target_log.slave_origin_uid)[1] if target_log.slave_member_uid: trgt_msg.author = ETMChat( db=self.db, channel=coordinator.slaves[target_channel]) trgt_msg.author.chat_name = target_log.slave_member_display_name trgt_msg.author.chat_alias = target_log.slave_member_display_name trgt_msg.author.chat_uid = target_log.slave_member_uid elif target_log.sent_to == 'master': trgt_msg.author = trgt_msg.chat else: trgt_msg.author = ETMChat(db=self.db, channel=self.channel).self() m.target = trgt_msg self.logger.debug( "[%s] This message replies to another message of the same channel.\n" "Chat ID: %s; Message ID: %s.", message_id, trgt_msg.chat.chat_uid, trgt_msg.uid) # Type specific stuff self.logger.debug("[%s] Message type from Telegram: %s", message_id, mtype) if self.TYPE_DICT.get(mtype, None): m.type = self.TYPE_DICT[mtype] self.logger.debug("[%s] EFB message type: %s", message_id, mtype) else: self.logger.info( "[%s] Message type %s is not supported by ETM", message_id, mtype) raise EFBMessageTypeNotSupported( self._("Message type {} is not supported by ETM.").format( mtype.name)) if m.type not in coordinator.slaves[ channel].supported_message_types: self.logger.info( "[%s] Message type %s is not supported by channel %s", message_id, m.type.name, channel) raise EFBMessageTypeNotSupported( self._("Message type {0} is not supported by channel {1}." ).format(m.type.name, coordinator.slaves[channel].channel_name)) # Parse message text and caption to markdown msg_md_text = message.text and message.text_markdown if msg_md_text and msg_md_text == escape_markdown(message.text): msg_md_text = message.text msg_md_text = msg_md_text or "" msg_md_caption = message.caption and message.caption_markdown if msg_md_caption and msg_md_caption == escape_markdown( message.caption): msg_md_caption = message.caption msg_md_caption = msg_md_caption or "" # Flag for edited message if edited: m.edit = True text = msg_md_text or msg_md_caption msg_log = self.db.get_msg_log( master_msg_id=utils.message_id_to_str(update=update)) if not msg_log or msg_log == self.FAIL_FLAG: raise EFBMessageNotFound() m.uid = msg_log.slave_message_id if text.startswith(self.DELETE_FLAG): coordinator.send_status( EFBMessageRemoval( source_channel=self.channel, destination_channel=coordinator.slaves[channel], message=m)) self.db.delete_msg_log( master_msg_id=utils.message_id_to_str(update=update)) log_message = False return self.logger.debug('[%s] Message is edited (%s)', m.uid, m.edit) # Enclose message as an EFBMsg object by message type. if mtype == TGMsgType.Text: m.text = msg_md_text elif mtype == TGMsgType.Photo: m.text = msg_md_caption m.mime = "image/jpeg" self._check_file_download(message.photo[-1]) elif mtype in (TGMsgType.Sticker, TGMsgType.AnimatedSticker): # Convert WebP to the more common PNG m.text = "" self._check_file_download(message.sticker) elif mtype == TGMsgType.Animation: m.text = "" self.logger.debug( "[%s] Telegram message is a \"Telegram GIF\".", message_id) m.filename = getattr(message.document, "file_name", None) or None m.mime = message.document.mime_type or m.mime elif mtype == TGMsgType.Document: m.text = msg_md_caption self.logger.debug("[%s] Telegram message type is document.", message_id) m.filename = getattr(message.document, "file_name", None) or None m.mime = message.document.mime_type self._check_file_download(message.document) elif mtype == TGMsgType.Video: m.text = msg_md_caption m.mime = message.video.mime_type self._check_file_download(message.video) elif mtype == TGMsgType.Audio: m.text = "%s - %s\n%s" % (message.audio.title, message.audio.performer, msg_md_caption) m.mime = message.audio.mime_type self._check_file_download(message.audio) elif mtype == TGMsgType.Voice: m.text = msg_md_caption m.mime = message.voice.mime_type self._check_file_download(message.voice) elif mtype == TGMsgType.Location: # TRANSLATORS: Message body text for location messages. m.text = self._("Location") m.attributes = EFBMsgLocationAttribute( message.location.latitude, message.location.longitude) elif mtype == TGMsgType.Venue: m.text = message.location.title + "\n" + message.location.adderss m.attributes = EFBMsgLocationAttribute( message.venue.location.latitude, message.venue.location.longitude) elif mtype == TGMsgType.Contact: contact: telegram.Contact = message.contact m.text = self._( "Shared a contact: {first_name} {last_name}\n{phone_number}" ).format(first_name=contact.first_name, last_name=contact.last_name, phone_number=contact.phone_number) else: raise EFBMessageTypeNotSupported( self._("Message type {0} is not supported.").format(mtype)) slave_msg = coordinator.send_message(m) except EFBChatNotFound as e: self.bot.reply_error(update, e.args[0] or self._("Chat is not found.")) except EFBMessageTypeNotSupported as e: self.bot.reply_error( update, e.args[0] or self._("Message type is not supported.")) except EFBOperationNotSupported as e: self.bot.reply_error( update, self._("Message editing is not supported.\n\n{!s}".format(e))) except Exception as e: self.bot.reply_error( update, self._("Message is not sent.\n\n{!r}".format(e))) self.logger.exception("Message is not sent. (update: %s)", update) finally: if log_message: pickled_msg = m.pickle(self.db) self.logger.debug("[%s] Pickle size: %s", message_id, len(pickled_msg)) msg_log_d = { "master_msg_id": utils.message_id_to_str(update=update), "text": m.text or "Sent a %s" % m.type.name, "slave_origin_uid": utils.chat_id_to_str(chat=m.chat), "slave_origin_display_name": "__chat__", "msg_type": m.type.name, "sent_to": "slave", "slave_message_id": None if m.edit else "%s.%s" % (self.FAIL_FLAG, int(time.time())), # Overwritten later if slave message ID exists "update": m.edit, "media_type": m.type_telegram.value, "file_id": m.file_id, "mime": m.mime, "pickle": pickled_msg } if slave_msg: msg_log_d['slave_message_id'] = slave_msg.uid # self.db.add_msg_log(**msg_log_d) self.db.add_task(self.db.add_msg_log, tuple(), msg_log_d) if m.file: m.file.close()
def send_message(self, msg: Message) -> Message: self.logger.debug("Received message: %r", msg) self.messages.put(msg) msg.uid = MessageID(str(uuid4())) self.messages_sent[msg.uid] = msg return msg