from __future__ import annotations import logging from datetime import UTC, datetime logger = logging.getLogger(__name__) def convert_dm_event_to_unified(event: dict, account_id: str) -> dict | None: event_id = str(event.get("id", "")) event_type = event.get("event_type", "") if event_type != "MessageCreate": return None text = event.get("text", "") sender_id = str(event.get("sender_id", "")) conversation_id = str(event.get("dm_conversation_id", "")) participant_ids = event.get("participant_ids", []) chat_type = "direct" if len(participant_ids) <= 2 else "group" attachments = event.get("attachments", []) media_urls: list[str] = [] attachment_media_id = None attachment_type = None if attachments: att = attachments[0] attachment_media_id = att.get("media_key", "") attachment_type = att.get("type", "") if attachment_media_id: media_urls.append(attachment_media_id) created_at = event.get("created_at", "") timestamp = None if created_at: try: timestamp = datetime.fromisoformat(created_at.replace("Z", "+00:00")) except ValueError: pass referenced_tweets = event.get("referenced_tweets", []) reply_to_id = None for ref in referenced_tweets: if ref.get("type") == "replied_to": reply_to_id = str(ref.get("id", "")) break return { "msg_id": f"tw:{event_id}", "channel_type": "twitter", "account_id": account_id, "content": text, "message_type": ( "IMAGE" if attachment_type == "photo" else ("VIDEO" if attachment_type == "video" else "TEXT") ), "media_urls": media_urls, "sender": { "id": sender_id, "display_name": f"twitter:{sender_id}", "kind": "DIRECT" if chat_type == "direct" else "GROUP", }, "group": ( { "id": conversation_id, "kind": chat_type, } if chat_type == "group" else None ), "timestamp": timestamp, "reply_to_id": reply_to_id, "thread_id": None, "raw_payload": event, } def convert_group_event_to_unified(event: dict, account_id: str) -> dict | None: event_type = event.get("event_type", "") if event_type not in ("ParticipantsJoin", "ParticipantsLeave"): return None event_id = str(event.get("id", "")) conversation_id = str(event.get("dm_conversation_id", "")) participant_ids = [str(pid) for pid in event.get("participant_ids", [])] action = "joined" if event_type == "ParticipantsJoin" else "left" description = f"Users {action} the group DM" created_at = event.get("created_at", "") timestamp = None if created_at: try: timestamp = datetime.fromisoformat(created_at.replace("Z", "+00:00")) except ValueError: pass return { "msg_id": f"tw:{event_id}", "channel_type": "twitter", "account_id": account_id, "content": description, "message_type": "EVENT", "media_urls": [], "sender": { "id": participant_ids[0] if participant_ids else "", "display_name": f"twitter:{participant_ids[0]}" if participant_ids else "", "kind": "GROUP", }, "group": {"id": conversation_id, "kind": "group"}, "timestamp": timestamp, "reply_to_id": None, "thread_id": None, "raw_payload": event, "metadata": { "event_type": event_type, "participant_ids": participant_ids, }, } def convert_webhook_event_to_unified( dm_event: dict, for_user_id: str, account_id: str ) -> dict | None: event_type = dm_event.get("type", "") if event_type != "message_create": return None event_id = str(dm_event.get("id", "")) msg_data = dm_event.get("message_create", {}) sender_id = str(msg_data.get("sender_id", "")) message_data = msg_data.get("message_data", {}) text = message_data.get("text", "") attachment = message_data.get("attachment", {}) media_urls: list[str] = [] if attachment.get("type") == "media": media = attachment.get("media", {}) media_url = media.get("media_url_https", "") if media_url: media_urls.append(media_url) created_timestamp = dm_event.get("created_timestamp", "") timestamp = None if created_timestamp: try: ts = int(created_timestamp) / 1000 timestamp = datetime.fromtimestamp(ts, tz=UTC) except (ValueError, OSError): pass return { "msg_id": f"tw:{event_id}", "channel_type": "twitter", "account_id": account_id, "content": text, "message_type": "IMAGE" if media_urls else "TEXT", "media_urls": media_urls, "sender": { "id": sender_id, "display_name": f"twitter:{sender_id}", "kind": "DIRECT", }, "group": None, "timestamp": timestamp, "reply_to_id": None, "thread_id": None, "raw_payload": dm_event, }