Skip to content

Commit

Permalink
feat: link in markup
Browse files Browse the repository at this point in the history
  • Loading branch information
kutuzov13 committed Apr 11, 2024
1 parent 6b27924 commit a03016d
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 3 deletions.
22 changes: 20 additions & 2 deletions pybotx/models/message/markup.py
Expand Up @@ -14,8 +14,8 @@ class ButtonTextAlign(Enum):

@dataclass
class Button:
command: str
label: str
command: Missing[str] = Undefined
data: Dict[str, Any] = field(default_factory=dict)
text_color: Missing[str] = Undefined
background_color: Missing[str] = Undefined
Expand All @@ -25,6 +25,7 @@ class Button:
width_ratio: Missing[int] = Undefined
alert: Missing[str] = Undefined
process_on_client: Missing[bool] = Undefined
link: Missing[str] = Undefined


ButtonRow = List[Button]
Expand Down Expand Up @@ -68,8 +69,8 @@ def add_built_button(self, button: Button, new_row: bool = True) -> None:

def add_button(
self,
command: str,
label: str,
command: Missing[str] = Undefined,
data: Optional[Dict[str, Any]] = None,
text_color: Missing[str] = Undefined,
background_color: Missing[str] = Undefined,
Expand All @@ -78,8 +79,19 @@ def add_button(
width_ratio: Missing[int] = Undefined,
alert: Missing[str] = Undefined,
process_on_client: Missing[bool] = Undefined,
link: Missing[str] = Undefined,
new_row: bool = True,
) -> None:
"""
Test that adding a button without a command raises a ValueError.
When a button is added without a command specified, a ValueError should raise
to indicate that the 'command' argument is required.
"""

if link is Undefined and command is Undefined:
raise ValueError("Command arg is required")

button = Button(
command=command,
label=label,
Expand All @@ -91,6 +103,7 @@ def add_button(
width_ratio=width_ratio,
alert=alert,
process_on_client=process_on_client,
link=link,
)
self.add_built_button(button, new_row=new_row)

Expand Down Expand Up @@ -118,6 +131,7 @@ class BotXAPIButtonOptions(UnverifiedPayloadBaseModel):
show_alert: Missing[Literal[True]]
alert_text: Missing[str]
handler: Missing[Literal["client"]]
link: Missing[str]


class BotXAPIButton(UnverifiedPayloadBaseModel):
Expand All @@ -140,6 +154,9 @@ def api_button_from_domain(button: Button) -> BotXAPIButton:
if button.process_on_client:
handler = "client"

if button.link is not Undefined:
handler = "client"

return BotXAPIButton(
command=button.command,
label=button.label,
Expand All @@ -153,6 +170,7 @@ def api_button_from_domain(button: Button) -> BotXAPIButton:
alert_text=button.alert,
show_alert=show_alert,
handler=handler,
link=button.link,
),
)

Expand Down
114 changes: 114 additions & 0 deletions tests/client/notifications_api/test_markup.py
Expand Up @@ -374,9 +374,123 @@ async def test__markup__color_and_align(
assert endpoint.called


async def test__markup__link(
respx_mock: MockRouter,
host: str,
bot_id: UUID,
bot_account: BotAccountWithSecret,
) -> None:
# - Arrange -
endpoint = respx_mock.post(
f"https://{host}/api/v4/botx/notifications/direct",
headers={"Authorization": "Bearer token", "Content-Type": "application/json"},
json={
"group_chat_id": "054af49e-5e18-4dca-ad73-4f96b6de63fa",
"notification": {
"body": "Buttons links:",
"bubble": [
[
{
"data": {},
"label": "Open me",
"opts": {
"silent": True,
"align": "center",
"handler": "client",
"link": "https://example.com",
},
},
],
],
"keyboard": [
[
{
"data": {},
"label": "Open me",
"opts": {
"silent": True,
"align": "center",
"handler": "client",
"link": "https://example.com",
},
},
],
],
"status": "ok",
},
},
).mock(
return_value=httpx.Response(
HTTPStatus.ACCEPTED,
json={
"status": "ok",
"result": {"sync_id": "21a9ec9e-f21f-4406-ac44-1a78d2ccf9e3"},
},
),
)

bubbles = BubbleMarkup()
bubbles.add_button(
label="Open me",
silent=True,
link="https://example.com",
)

keyboard = KeyboardMarkup()
keyboard.add_button(
label="Open me",
silent=True,
link="https://example.com",
)

built_bot = Bot(collectors=[HandlerCollector()], bot_accounts=[bot_account])

# - Act -
async with lifespan_wrapper(built_bot) as bot:
task = asyncio.create_task(
bot.send_message(
body="Buttons links:",
bot_id=bot_id,
chat_id=UUID("054af49e-5e18-4dca-ad73-4f96b6de63fa"),
bubbles=bubbles,
keyboard=keyboard,
),
)

await asyncio.sleep(0) # Return control to event loop

await bot.set_raw_botx_method_result(
{
"status": "ok",
"sync_id": "21a9ec9e-f21f-4406-ac44-1a78d2ccf9e3",
"result": {},
},
verify_request=False,
)

# - Assert -
assert (await task) == UUID("21a9ec9e-f21f-4406-ac44-1a78d2ccf9e3")
assert endpoint.called


def test__markup__comparison() -> None:
# - Arrange -
button = Button("/test", "test")

# - Assert -
assert BubbleMarkup([[button]]) == BubbleMarkup([[button]])


def test__markup__bubble_without_command_error_raised() -> None:
# - Arrange -
bubbles = BubbleMarkup()

# - Act -
with pytest.raises(ValueError) as exc:
bubbles.add_button(
label="label",
silent=True,
)

# - Assert -
assert "Command arg is required" in str(exc.value)
2 changes: 1 addition & 1 deletion tests/models/test_markup.py
Expand Up @@ -11,5 +11,5 @@ def test__mentions_list_properties__filled() -> None:
# - Assert -
assert (
bubbles.__repr__()
== "row 1: label1 (command1)\nrow 2: label2 (command2) | label3 (command3)"
== "row 1: command1 (label1)\nrow 2: command2 (label2) | command3 (label3)"
)

0 comments on commit a03016d

Please sign in to comment.