Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions telebot/formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,13 +423,13 @@ def format_entity(entity, content):
# username = content[1:] # Remove @ symbol
# return f"<a href=\"https://t.me/{username}\">{content}</a>"
elif entity_type == "text_link" and hasattr(entity, 'url'):
return _subs["text_link"].format(url=entity.url, text=content)
return _subs["text_link"].format(url=escape_html(entity.url), text=content)
elif entity_type == "custom_emoji" and hasattr(entity, 'custom_emoji_id'):
return _subs["custom_emoji"].format(custom_emoji_id=entity.custom_emoji_id, text=content)
elif entity_type == "date_time" and hasattr(entity, 'unix_time') and hasattr(entity, 'date_time_format'):
return _subs["date_time"].format(unix=entity.unix_time, date_time_format=entity.date_time_format, text=content)
return _subs["date_time"].format(unix_time=entity.unix_time, date_time_format=entity.date_time_format, text=content)
elif entity_type == "pre" and hasattr(entity, 'language') and entity.language:
return f"<pre><code class=\"language-{entity.language}\">{content}</code></pre>"
return f"<pre><code class=\"language-{escape_html(entity.language)}\">{content}</code></pre>"
elif entity_type in _subs:
template = _subs[entity_type]
return template.format(text=content)
Expand Down
3 changes: 2 additions & 1 deletion telebot/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ def extract_arguments(text: str) -> Union[str, None]:
:rtype: :obj:`str` or :obj:`None`
"""
regexp = re.compile(r"/\w*(@\w*)*\s*([\s\S]*)", re.IGNORECASE)
if text is None: return None
result = regexp.match(text)
return result.group(2) if is_command(text) else None

Expand Down Expand Up @@ -357,7 +358,7 @@ def _text_before_last(substr: str) -> str:

parts = []
while True:
if len(text) < chars_per_string:
if len(text) <= chars_per_string:
parts.append(text)
return parts

Expand Down
41 changes: 40 additions & 1 deletion tests/test_formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

from html.parser import HTMLParser

from telebot.formatting import hpre
from telebot import types
from telebot.formatting import apply_html_entities, hpre


class AttributeCollector(HTMLParser):
Expand Down Expand Up @@ -35,3 +36,41 @@ def test_hpre_language_cannot_add_attributes():

def test_hpre_still_escapes_content():
assert hpre("<b>", language="python") == '<pre><code class="python">&lt;b&gt;</code></pre>'


def test_apply_html_entities_date_time():
# used to raise KeyError: 'unix_time' because the template was formatted with
# unix= while it declares {unix_time}
entity = types.MessageEntity(
type="date_time", offset=11, length=5,
unix_time=1735689600, date_time_format="r"
)
assert apply_html_entities("Meeting at 10:00", [entity]) == (
'Meeting at <tg-time unix="1735689600" format="r">10:00</tg-time>'
)


def test_apply_html_entities_escapes_link_url():
entity = types.MessageEntity(
type="text_link", offset=0, length=4, url='https://x.test/?a="b'
)
parser = AttributeCollector()
parser.feed(apply_html_entities("link rest", [entity]))
assert parser.tags == [("a", [("href", 'https://x.test/?a="b')])]


def test_apply_html_entities_escapes_pre_language():
entity = types.MessageEntity(
type="pre", offset=0, length=4, language='py" onload="x'
)
parser = AttributeCollector()
parser.feed(apply_html_entities("code rest", [entity]))
assert parser.tags == [
("pre", []),
("code", [("class", 'language-py" onload="x')]),
]


def test_apply_html_entities_still_escapes_content():
entity = types.MessageEntity(type="bold", offset=0, length=4)
assert apply_html_entities("a<b> c", [entity]) == "<b>a&lt;b&gt;</b> c"
38 changes: 38 additions & 0 deletions tests/test_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from telebot import util


def test_smart_split_exact_multiple_has_no_trailing_empty_part():
# A chunk boundary landing exactly on the limit used to append an empty part.
for size in (1, 2, 3, 4, 10):
for chunks in (1, 2, 3):
text = "a" * (size * chunks)
assert util.smart_split(text, size) == ["a" * size] * chunks


def test_smart_split_short_text():
assert util.smart_split("abc", 3) == ["abc"]
assert util.smart_split("abcde", 3) == ["abc", "de"]
assert util.smart_split("", 3) == [""]


def test_smart_split_prefers_newline_then_space():
assert util.smart_split("one two\nthree four", 10) == ["one two\n", "three four"]
assert util.smart_split("one two three", 8) == ["one two ", "three"]


def test_smart_split_caps_at_max_message_length():
parts = util.smart_split("a" * (util.MAX_MESSAGE_LENGTH * 2), util.MAX_MESSAGE_LENGTH * 5)
assert [len(p) for p in parts] == [util.MAX_MESSAGE_LENGTH] * 2


def test_extract_arguments_accepts_none():
# message.text is None for non-text messages
assert util.extract_arguments(None) is None # type: ignore[arg-type]
assert util.extract_command(None) is None # type: ignore[arg-type]


def test_extract_arguments_values():
assert util.extract_arguments("/get name") == "name"
assert util.extract_arguments("/get") == ""
assert util.extract_arguments("/get@bot name") == "name"
assert util.extract_arguments("hello") is None
Loading