import time import logging from yuxi.channel.extensions.tlon.story import markdown_to_story from yuxi.channel.extensions.tlon.utils import format_at_ud, normalize_ship logger = logging.getLogger(__name__) async def send_dm(api, from_ship: str, to_ship: str, text: str) -> str: story = markdown_to_story(text) return await send_dm_with_story(api, from_ship, to_ship, story) async def send_dm_with_story(api, from_ship: str, to_ship: str, story: list[dict]) -> str: msg_id = f"{from_ship}/{int(time.time() * 1000)}" payload = { "ship": to_ship, "diff": { "id": msg_id, "delta": { "add": { "memo": { "content": story, "author": from_ship, "sent": int(time.time() * 1000), }, "kind": None, "time": None, } } } } await api.poke(app="chat", mark="chat-dm-action", json_data=payload) return msg_id async def send_group_message(api, from_ship: str, host_ship: str, channel_name: str, text: str, reply_to_id: str | None = None) -> str: story = markdown_to_story(text) return await send_group_message_with_story( api, from_ship, host_ship, channel_name, story, reply_to_id ) async def send_group_message_with_story(api, from_ship: str, host_ship: str, channel_name: str, story: list[dict], reply_to_id: str | None = None) -> str: nest = f"chat/{host_ship}/{channel_name}" if reply_to_id: action = { "post": { "reply": { "id": format_at_ud(reply_to_id), "action": { "add": { "content": story, "author": from_ship, "sent": int(time.time() * 1000), } } } } } else: action = { "post": { "add": { "content": story, "author": from_ship, "sent": int(time.time() * 1000), "kind": "/chat", "blob": None, "meta": None, } } } payload = {"channel": {"nest": nest, "action": action}} await api.poke(app="channels", mark="channel-action-1", json_data=payload) return f"{from_ship}/{int(time.time() * 1000)}" async def add_reaction_group(api, from_ship: str, host_ship: str, channel_name: str, msg_id: str, emoji: str) -> None: nest = f"chat/{host_ship}/{channel_name}" payload = { "channel": { "nest": nest, "action": { "post": { "add-react": { "id": format_at_ud(msg_id), "react": emoji, "ship": from_ship, } } } } } await api.poke(app="channels", mark="channel-action-1", json_data=payload) async def remove_reaction_group(api, from_ship: str, host_ship: str, channel_name: str, msg_id: str, emoji: str) -> None: nest = f"chat/{host_ship}/{channel_name}" payload = { "channel": { "nest": nest, "action": { "post": { "del-react": { "id": format_at_ud(msg_id), "react": emoji, "ship": from_ship, } } } } } await api.poke(app="channels", mark="channel-action-1", json_data=payload) async def add_reaction_dm(api, from_ship: str, to_ship: str, msg_id: str, emoji: str) -> None: payload = { "ship": to_ship, "diff": { "id": format_at_ud(msg_id), "delta": { "add-react": { "react": emoji, "ship": from_ship, } } } } await api.poke(app="chat", mark="chat-dm-action-1", json_data=payload) async def create_club_dm(api, from_ship: str, members: list[str], title: str = "") -> str: club_id = f"{from_ship}/{int(time.time() * 1000)}" payload = { "create": { "id": club_id, "members": [normalize_ship(s) for s in members], "title": title or f"Club ({len(members)} members)", } } await api.poke(app="chat", mark="chat-club-create", json_data=payload) return club_id async def send_club_message(api, from_ship: str, club_id: str, text: str) -> str: story = markdown_to_story(text) msg_id = f"{from_ship}/{int(time.time() * 1000)}" payload = { "id": msg_id, "delta": { "add": { "memo": { "content": story, "author": from_ship, "sent": int(time.time() * 1000), } } } } await api.poke(app="chat", mark="chat-club-action-0", json_data={ "id": club_id, "diff": payload, }) return msg_id async def pin_message(api, nest: str, msg_id: str, pin: bool = True) -> None: action = "pin" if pin else "unpin" payload = { "channel": { "nest": nest, "action": {"post": {action: format_at_ud(msg_id)}}, } } await api.poke(app="channels", mark="channel-action-1", json_data=payload) async def send_poll_dm(api, to_ship: str, from_ship: str, question: str, options: list[str]) -> str: msg_id = f"{from_ship}/{int(time.time() * 1000)}" story = [{ "block": { "poll": { "question": question, "options": [{"label": opt} for opt in options], "author": from_ship, } } }] payload = { "ship": to_ship, "diff": { "id": msg_id, "delta": { "add": { "memo": { "content": story, "author": from_ship, "sent": int(time.time() * 1000), } } } } } await api.poke(app="chat", mark="chat-dm-action-1", json_data=payload) return msg_id async def send_poll_group(api, from_ship: str, host_ship: str, channel_name: str, question: str, options: list[str]) -> str: story = [{ "block": { "poll": { "question": question, "options": [{"label": opt} for opt in options], "author": from_ship, } } }] nest = f"chat/{host_ship}/{channel_name}" payload = { "channel": { "nest": nest, "action": { "post": { "add": { "content": story, "author": from_ship, "sent": int(time.time() * 1000), } } } } } await api.poke(app="channels", mark="channel-action-1", json_data=payload) return f"{from_ship}/{int(time.time() * 1000)}" async def remove_reaction_dm(api, from_ship: str, to_ship: str, msg_id: str, emoji: str) -> None: payload = { "ship": to_ship, "diff": { "id": format_at_ud(msg_id), "delta": { "del-react": { "react": emoji, "ship": from_ship, } } } } await api.poke(app="chat", mark="chat-dm-action-1", json_data=payload) async def edit_group_message(api, from_ship: str, host_ship: str, channel_name: str, msg_id: str, new_text: str) -> None: story = markdown_to_story(new_text) nest = f"chat/{host_ship}/{channel_name}" payload = { "channel": { "nest": nest, "action": { "post": { "edit": { "id": format_at_ud(msg_id), "content": story, } } } } } await api.poke(app="channels", mark="channel-action-1", json_data=payload) async def edit_dm_message(api, from_ship: str, to_ship: str, msg_id: str, new_text: str) -> None: story = markdown_to_story(new_text) payload = { "ship": to_ship, "diff": { "id": format_at_ud(msg_id), "delta": { "edit": { "content": story, } } } } await api.poke(app="chat", mark="chat-dm-action-1", json_data=payload) async def delete_group_message(api, host_ship: str, channel_name: str, msg_id: str) -> None: nest = f"chat/{host_ship}/{channel_name}" payload = { "channel": { "nest": nest, "action": { "post": { "del": format_at_ud(msg_id), } } } } await api.poke(app="channels", mark="channel-action-1", json_data=payload) async def delete_dm_message(api, to_ship: str, msg_id: str) -> None: payload = { "ship": to_ship, "diff": { "id": format_at_ud(msg_id), "delta": { "del": None, } } } await api.poke(app="chat", mark="chat-dm-action-1", json_data=payload)