mirror of
https://github.com/aiogram/aiogram.git
synced 2026-04-08 16:37:47 +00:00
* Add set_chat_member_tag shortcut coverage * Add set_member_tag shortcut tests and align decoration expectations * Fix follow-up test coverage for sender_tag and can_edit_tag * Add changelog fragment for PR 1781 * Align changelog with base PR #1780 * Expand 1780 changelog to cover base and follow-up scope * Treat sender_tag as metadata, not message content type --------- Co-authored-by: Latand <latand@users.noreply.github.com> Co-authored-by: Codex Agent <codex@openclaw.local>
This commit is contained in:
parent
251df4b193
commit
ebfab22d64
13 changed files with 202 additions and 8 deletions
|
|
@ -39,6 +39,7 @@ extract:
|
||||||
- reply_to_story
|
- reply_to_story
|
||||||
- business_connection_id
|
- business_connection_id
|
||||||
- sender_business_bot
|
- sender_business_bot
|
||||||
|
- sender_tag
|
||||||
- is_from_offline
|
- is_from_offline
|
||||||
- has_media_spoiler
|
- has_media_spoiler
|
||||||
- effect_id
|
- effect_id
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,10 @@ set_administrator_custom_title:
|
||||||
method: setChatAdministratorCustomTitle
|
method: setChatAdministratorCustomTitle
|
||||||
fill: *self
|
fill: *self
|
||||||
|
|
||||||
|
set_member_tag:
|
||||||
|
method: setChatMemberTag
|
||||||
|
fill: *self
|
||||||
|
|
||||||
set_permissions:
|
set_permissions:
|
||||||
method: setChatPermissions
|
method: setChatPermissions
|
||||||
fill: *self
|
fill: *self
|
||||||
|
|
|
||||||
1
CHANGES/1780.feature.rst
Normal file
1
CHANGES/1780.feature.rst
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Added full Telegram Bot API 9.5 support across aiogram: new API methods (``sendChecklist``, ``sendMessageDraft``, ``setChatMemberTag``, ``editMessageChecklist``), updated chat member/tag capability fields (including ``can_manage_tags``, ``can_edit_tag``, ``tag`` and ``sender_tag``), updated message/content-type and ``MessageEntity`` handling (including date-time entity formatting), regenerated API/docs artifacts, and follow-up shortcut/codegen/test coverage for ``Chat.set_member_tag(...)`` and related tag behaviors.
|
||||||
|
|
@ -8,7 +8,6 @@ class ContentType(str, Enum):
|
||||||
|
|
||||||
UNKNOWN = "unknown"
|
UNKNOWN = "unknown"
|
||||||
ANY = "any"
|
ANY = "any"
|
||||||
SENDER_TAG = "sender_tag"
|
|
||||||
TEXT = "text"
|
TEXT = "text"
|
||||||
ANIMATION = "animation"
|
ANIMATION = "animation"
|
||||||
AUDIO = "audio"
|
AUDIO = "audio"
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ if TYPE_CHECKING:
|
||||||
SendChatAction,
|
SendChatAction,
|
||||||
SetChatAdministratorCustomTitle,
|
SetChatAdministratorCustomTitle,
|
||||||
SetChatDescription,
|
SetChatDescription,
|
||||||
|
SetChatMemberTag,
|
||||||
SetChatPermissions,
|
SetChatPermissions,
|
||||||
SetChatPhoto,
|
SetChatPhoto,
|
||||||
SetChatStickerSet,
|
SetChatStickerSet,
|
||||||
|
|
@ -967,6 +968,38 @@ class Chat(TelegramObject):
|
||||||
**kwargs,
|
**kwargs,
|
||||||
).as_(self._bot)
|
).as_(self._bot)
|
||||||
|
|
||||||
|
def set_member_tag(
|
||||||
|
self,
|
||||||
|
user_id: int,
|
||||||
|
tag: str | None = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
) -> SetChatMemberTag:
|
||||||
|
"""
|
||||||
|
Shortcut for method :class:`aiogram.methods.set_chat_member_tag.SetChatMemberTag`
|
||||||
|
will automatically fill method attributes:
|
||||||
|
|
||||||
|
- :code:`chat_id`
|
||||||
|
|
||||||
|
Use this method to set a tag for a regular member in a group or a supergroup. The bot must be an administrator in the chat for this to work and must have the *can_manage_tags* administrator right. Returns :code:`True` on success.
|
||||||
|
|
||||||
|
Source: https://core.telegram.org/bots/api#setchatmembertag
|
||||||
|
|
||||||
|
:param user_id: Unique identifier of the target user
|
||||||
|
:param tag: New tag for the member; 0-16 characters, emoji are not allowed
|
||||||
|
:return: instance of method :class:`aiogram.methods.set_chat_member_tag.SetChatMemberTag`
|
||||||
|
"""
|
||||||
|
# DO NOT EDIT MANUALLY!!!
|
||||||
|
# This method was auto-generated via `butcher`
|
||||||
|
|
||||||
|
from aiogram.methods import SetChatMemberTag
|
||||||
|
|
||||||
|
return SetChatMemberTag(
|
||||||
|
chat_id=self.id,
|
||||||
|
user_id=user_id,
|
||||||
|
tag=tag,
|
||||||
|
**kwargs,
|
||||||
|
).as_(self._bot)
|
||||||
|
|
||||||
def set_permissions(
|
def set_permissions(
|
||||||
self,
|
self,
|
||||||
permissions: ChatPermissions,
|
permissions: ChatPermissions,
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,11 @@ class TestPromoteChatMember:
|
||||||
async def test_bot_method(self, bot: MockedBot):
|
async def test_bot_method(self, bot: MockedBot):
|
||||||
prepare_result = bot.add_result_for(PromoteChatMember, ok=True, result=True)
|
prepare_result = bot.add_result_for(PromoteChatMember, ok=True, result=True)
|
||||||
|
|
||||||
response: bool = await bot.promote_chat_member(chat_id=-42, user_id=42)
|
response: bool = await bot.promote_chat_member(
|
||||||
bot.get_request()
|
chat_id=-42,
|
||||||
|
user_id=42,
|
||||||
|
can_manage_tags=True,
|
||||||
|
)
|
||||||
|
request = bot.get_request()
|
||||||
|
assert request.can_manage_tags is True
|
||||||
assert response == prepare_result.result
|
assert response == prepare_result.result
|
||||||
|
|
|
||||||
14
tests/test_api/test_methods/test_set_chat_member_tag.py
Normal file
14
tests/test_api/test_methods/test_set_chat_member_tag.py
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
from aiogram.methods import SetChatMemberTag
|
||||||
|
from tests.mocked_bot import MockedBot
|
||||||
|
|
||||||
|
|
||||||
|
class TestSetChatMemberTag:
|
||||||
|
async def test_bot_method(self, bot: MockedBot):
|
||||||
|
prepare_result = bot.add_result_for(SetChatMemberTag, ok=True, result=True)
|
||||||
|
|
||||||
|
response: bool = await bot.set_chat_member_tag(chat_id=-42, user_id=42, tag="test")
|
||||||
|
request = bot.get_request()
|
||||||
|
assert request.chat_id == -42
|
||||||
|
assert request.user_id == 42
|
||||||
|
assert request.tag == "test"
|
||||||
|
assert response == prepare_result.result
|
||||||
|
|
@ -115,6 +115,14 @@ class TestChat:
|
||||||
method = chat.set_administrator_custom_title(user_id=1, custom_title="test")
|
method = chat.set_administrator_custom_title(user_id=1, custom_title="test")
|
||||||
assert method.chat_id == chat.id
|
assert method.chat_id == chat.id
|
||||||
|
|
||||||
|
def test_set_member_tag(self):
|
||||||
|
chat = Chat(id=-42, type="supergroup")
|
||||||
|
|
||||||
|
method = chat.set_member_tag(user_id=42, tag="test")
|
||||||
|
assert method.chat_id == chat.id
|
||||||
|
assert method.user_id == 42
|
||||||
|
assert method.tag == "test"
|
||||||
|
|
||||||
def test_set_permissions(self):
|
def test_set_permissions(self):
|
||||||
chat = Chat(id=-42, type="supergroup")
|
chat = Chat(id=-42, type="supergroup")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from aiogram.types import (
|
||||||
|
ChatAdministratorRights,
|
||||||
|
ChatMemberAdministrator,
|
||||||
|
ChatMemberMember,
|
||||||
|
ChatMemberRestricted,
|
||||||
|
ChatPermissions,
|
||||||
|
User,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestChatMemberTagPermissions:
|
||||||
|
def test_chat_administrator_rights_can_manage_tags(self):
|
||||||
|
rights = ChatAdministratorRights(
|
||||||
|
is_anonymous=False,
|
||||||
|
can_manage_chat=True,
|
||||||
|
can_delete_messages=True,
|
||||||
|
can_manage_video_chats=True,
|
||||||
|
can_restrict_members=True,
|
||||||
|
can_promote_members=True,
|
||||||
|
can_change_info=True,
|
||||||
|
can_invite_users=True,
|
||||||
|
can_post_stories=True,
|
||||||
|
can_edit_stories=True,
|
||||||
|
can_delete_stories=True,
|
||||||
|
can_manage_tags=True,
|
||||||
|
)
|
||||||
|
assert rights.can_manage_tags is True
|
||||||
|
|
||||||
|
def test_chat_member_administrator_can_manage_tags(self):
|
||||||
|
admin = ChatMemberAdministrator(
|
||||||
|
user=User(id=42, is_bot=False, first_name="User"),
|
||||||
|
can_be_edited=True,
|
||||||
|
is_anonymous=False,
|
||||||
|
can_manage_chat=True,
|
||||||
|
can_delete_messages=True,
|
||||||
|
can_manage_video_chats=True,
|
||||||
|
can_restrict_members=True,
|
||||||
|
can_promote_members=True,
|
||||||
|
can_change_info=True,
|
||||||
|
can_invite_users=True,
|
||||||
|
can_post_stories=True,
|
||||||
|
can_edit_stories=True,
|
||||||
|
can_delete_stories=True,
|
||||||
|
can_manage_tags=True,
|
||||||
|
)
|
||||||
|
assert admin.can_manage_tags is True
|
||||||
|
|
||||||
|
def test_chat_permissions_can_edit_tag(self):
|
||||||
|
permissions = ChatPermissions(can_edit_tag=True)
|
||||||
|
assert permissions.can_edit_tag is True
|
||||||
|
|
||||||
|
def test_chat_member_member_tag(self):
|
||||||
|
member = ChatMemberMember(
|
||||||
|
user=User(id=42, is_bot=False, first_name="User"),
|
||||||
|
tag="premium",
|
||||||
|
)
|
||||||
|
assert member.tag == "premium"
|
||||||
|
|
||||||
|
def test_chat_member_restricted_can_edit_tag_and_tag(self):
|
||||||
|
restricted = ChatMemberRestricted(
|
||||||
|
user=User(id=42, is_bot=False, first_name="User"),
|
||||||
|
is_member=True,
|
||||||
|
can_send_messages=True,
|
||||||
|
can_send_audios=True,
|
||||||
|
can_send_documents=True,
|
||||||
|
can_send_photos=True,
|
||||||
|
can_send_videos=True,
|
||||||
|
can_send_video_notes=True,
|
||||||
|
can_send_voice_notes=True,
|
||||||
|
can_send_polls=True,
|
||||||
|
can_send_other_messages=True,
|
||||||
|
can_add_web_page_previews=True,
|
||||||
|
can_edit_tag=True,
|
||||||
|
can_change_info=True,
|
||||||
|
can_invite_users=True,
|
||||||
|
can_pin_messages=True,
|
||||||
|
can_manage_topics=True,
|
||||||
|
until_date=datetime.now(),
|
||||||
|
tag="premium",
|
||||||
|
)
|
||||||
|
assert restricted.can_edit_tag is True
|
||||||
|
assert restricted.tag == "premium"
|
||||||
|
|
@ -314,6 +314,7 @@ class TestChatMemberUpdatedStatusFilter:
|
||||||
"can_send_polls": True,
|
"can_send_polls": True,
|
||||||
"can_send_other_messages": True,
|
"can_send_other_messages": True,
|
||||||
"can_add_web_page_previews": True,
|
"can_add_web_page_previews": True,
|
||||||
|
"can_edit_tag": True,
|
||||||
"can_post_stories": True,
|
"can_post_stories": True,
|
||||||
"can_edit_stories": True,
|
"can_edit_stories": True,
|
||||||
"can_delete_stories": True,
|
"can_delete_stories": True,
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ CHAT_MEMBER_RESTRICTED = ChatMemberRestricted(
|
||||||
can_send_polls=False,
|
can_send_polls=False,
|
||||||
can_send_other_messages=False,
|
can_send_other_messages=False,
|
||||||
can_add_web_page_previews=False,
|
can_add_web_page_previews=False,
|
||||||
|
can_edit_tag=False,
|
||||||
can_change_info=False,
|
can_change_info=False,
|
||||||
can_invite_users=False,
|
can_invite_users=False,
|
||||||
can_pin_messages=False,
|
can_pin_messages=False,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ from aiogram.utils.formatting import (
|
||||||
CashTag,
|
CashTag,
|
||||||
Code,
|
Code,
|
||||||
CustomEmoji,
|
CustomEmoji,
|
||||||
|
DateTime,
|
||||||
Email,
|
Email,
|
||||||
ExpandableBlockQuote,
|
ExpandableBlockQuote,
|
||||||
HashTag,
|
HashTag,
|
||||||
|
|
@ -93,7 +94,7 @@ class TestNode:
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
Pre("test", language="python"),
|
Pre("test", language="python"),
|
||||||
'<pre><code class="language-python">test</code></pre>',
|
'<pre><code language="language-python">test</code></pre>',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
TextLink("test", url="https://example.com"),
|
TextLink("test", url="https://example.com"),
|
||||||
|
|
@ -105,7 +106,7 @@ class TestNode:
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
CustomEmoji("test", custom_emoji_id="42"),
|
CustomEmoji("test", custom_emoji_id="42"),
|
||||||
'<tg-emoji emoji-id="42">test</tg-emoji>',
|
'<tg-emoji emoji_id="42">test</tg-emoji>',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
BlockQuote("test"),
|
BlockQuote("test"),
|
||||||
|
|
@ -115,6 +116,10 @@ class TestNode:
|
||||||
ExpandableBlockQuote("test"),
|
ExpandableBlockQuote("test"),
|
||||||
"<blockquote expandable>test</blockquote>",
|
"<blockquote expandable>test</blockquote>",
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
DateTime("test", unix_time=42, date_time_format="yMd"),
|
||||||
|
'<tg-time unix="42" format="yMd">test</tg-time>',
|
||||||
|
],
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_render_plain_only(self, node: Text, result: str):
|
def test_render_plain_only(self, node: Text, result: str):
|
||||||
|
|
@ -358,6 +363,22 @@ class TestUtils:
|
||||||
assert isinstance(node, Bold)
|
assert isinstance(node, Bold)
|
||||||
assert node._body == ("test",)
|
assert node._body == ("test",)
|
||||||
|
|
||||||
|
def test_apply_entity_date_time(self):
|
||||||
|
node = _apply_entity(
|
||||||
|
MessageEntity(
|
||||||
|
type=MessageEntityType.DATE_TIME,
|
||||||
|
offset=0,
|
||||||
|
length=4,
|
||||||
|
unix_time=42,
|
||||||
|
date_time_format="yMd",
|
||||||
|
),
|
||||||
|
"test",
|
||||||
|
)
|
||||||
|
assert isinstance(node, DateTime)
|
||||||
|
assert node._body == ("test",)
|
||||||
|
assert node._params["unix_time"] == 42
|
||||||
|
assert node._params["date_time_format"] == "yMd"
|
||||||
|
|
||||||
def test_as_line(self):
|
def test_as_line(self):
|
||||||
node = as_line("test", "test", "test")
|
node = as_line("test", "test", "test")
|
||||||
assert isinstance(node, Text)
|
assert isinstance(node, Text)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ class TestTextDecoration:
|
||||||
[
|
[
|
||||||
html_decoration,
|
html_decoration,
|
||||||
MessageEntity(type="pre", offset=0, length=5, language="python"),
|
MessageEntity(type="pre", offset=0, length=5, language="python"),
|
||||||
'<pre><code class="language-python">test</code></pre>',
|
'<pre><code language="language-python">test</code></pre>',
|
||||||
],
|
],
|
||||||
[html_decoration, MessageEntity(type="underline", offset=0, length=5), "<u>test</u>"],
|
[html_decoration, MessageEntity(type="underline", offset=0, length=5), "<u>test</u>"],
|
||||||
[
|
[
|
||||||
|
|
@ -57,7 +57,7 @@ class TestTextDecoration:
|
||||||
[
|
[
|
||||||
html_decoration,
|
html_decoration,
|
||||||
MessageEntity(type="custom_emoji", offset=0, length=5, custom_emoji_id="42"),
|
MessageEntity(type="custom_emoji", offset=0, length=5, custom_emoji_id="42"),
|
||||||
'<tg-emoji emoji-id="42">test</tg-emoji>',
|
'<tg-emoji emoji_id="42">test</tg-emoji>',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
html_decoration,
|
html_decoration,
|
||||||
|
|
@ -74,6 +74,17 @@ class TestTextDecoration:
|
||||||
MessageEntity(type="expandable_blockquote", offset=0, length=5),
|
MessageEntity(type="expandable_blockquote", offset=0, length=5),
|
||||||
"<blockquote expandable>test</blockquote>",
|
"<blockquote expandable>test</blockquote>",
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
html_decoration,
|
||||||
|
MessageEntity(
|
||||||
|
type="date_time",
|
||||||
|
offset=0,
|
||||||
|
length=5,
|
||||||
|
unix_time=42,
|
||||||
|
date_time_format="yMd",
|
||||||
|
),
|
||||||
|
'<tg-time unix="42" format="yMd">test</tg-time>',
|
||||||
|
],
|
||||||
[markdown_decoration, MessageEntity(type="bold", offset=0, length=5), "*test*"],
|
[markdown_decoration, MessageEntity(type="bold", offset=0, length=5), "*test*"],
|
||||||
[markdown_decoration, MessageEntity(type="italic", offset=0, length=5), "_\rtest_\r"],
|
[markdown_decoration, MessageEntity(type="italic", offset=0, length=5), "_\rtest_\r"],
|
||||||
[markdown_decoration, MessageEntity(type="code", offset=0, length=5), "`test`"],
|
[markdown_decoration, MessageEntity(type="code", offset=0, length=5), "`test`"],
|
||||||
|
|
@ -102,7 +113,7 @@ class TestTextDecoration:
|
||||||
[
|
[
|
||||||
markdown_decoration,
|
markdown_decoration,
|
||||||
MessageEntity(type="custom_emoji", offset=0, length=5, custom_emoji_id="42"),
|
MessageEntity(type="custom_emoji", offset=0, length=5, custom_emoji_id="42"),
|
||||||
"",
|
"",
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
markdown_decoration,
|
markdown_decoration,
|
||||||
|
|
@ -124,6 +135,17 @@ class TestTextDecoration:
|
||||||
MessageEntity(type="expandable_blockquote", offset=0, length=5),
|
MessageEntity(type="expandable_blockquote", offset=0, length=5),
|
||||||
">test||",
|
">test||",
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
markdown_decoration,
|
||||||
|
MessageEntity(
|
||||||
|
type="date_time",
|
||||||
|
offset=0,
|
||||||
|
length=5,
|
||||||
|
unix_time=42,
|
||||||
|
date_time_format="yMd",
|
||||||
|
),
|
||||||
|
"",
|
||||||
|
],
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_apply_single_entity(
|
def test_apply_single_entity(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue