diff --git a/aiogram/types/chat.py b/aiogram/types/chat.py index 7d735ac3..6313abc4 100644 --- a/aiogram/types/chat.py +++ b/aiogram/types/chat.py @@ -54,3 +54,11 @@ class Chat(TelegramObject): """*Optional*. Unique identifier for the linked chat, i.e. the discussion group identifier for a channel and vice versa; for supergroups and channel chats. This identifier may be greater than 32 bits and some programming languages may have difficulty/silent defects in interpreting it. But it is smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" location: Optional[ChatLocation] = None """*Optional*. For supergroups, the location to which the supergroup is connected. Returned only in :class:`aiogram.methods.get_chat.GetChat`.""" + + @property + def shifted_id(self) -> int: + """ + Returns shifted chat ID (positive and without "-100" prefix. + Mostly used for private links like t.me/c/chat_id/message_id + """ + return abs(self.id + 1_000_000_000_000) diff --git a/aiogram/types/message.py b/aiogram/types/message.py index d476c099..f183faad 100644 --- a/aiogram/types/message.py +++ b/aiogram/types/message.py @@ -1714,6 +1714,26 @@ class Message(TelegramObject): reply_markup=reply_markup, ) + def get_url(self, force_private: bool = False) -> str: + """ + Returns message URL. Cannot be used in private (one-to-one) chats. + If chat has a username, returns URL like https://t.me/username/message_id + Otherwise (or if {force_private} flag is set), returns https://t.me/c/shifted_chat_id/message_id + + :param force_private: if set, a private URL is returned even for a public chat + :return: string with full message URL + """ + if self.chat.type == "private": + raise TypeError("Invalid chat type!") + + url = "https://t.me/" + if not self.chat.username or force_private: + url += f"c/{self.chat.shifted_id}/" + else: + url += f"{self.chat.username}/" + url += f"{self.message_id}" + return url + class ContentType(helper.Helper): mode = helper.HelperMode.snake_case