diff --git a/lib/content.py b/lib/content.py new file mode 100644 index 0000000..3ef20ae --- /dev/null +++ b/lib/content.py @@ -0,0 +1,133 @@ +from dataclasses import dataclass, field +from typing import Optional, List, Dict + +from .utils import EncryptedFile, ImageInfo, FileInfo, AudioInfo, VideoInfo, LocationInfo, PreviousRoom, Invite + + +@dataclass +class ContentBase: + pass + + +@dataclass +class MessageContentBase(ContentBase): + body: str + msgtype: str + + +@dataclass +class MTextContent(MessageContentBase): + format: Optional[str] = None + formatted_body: Optional[str] = None + msgtype = 'm.text' + + +@dataclass +class MEmoteContent(MTextContent): + msgtype = 'm.emote' + + +@dataclass +class MNoticeContent(MTextContent): + msgtype = 'm.notice' + + +@dataclass +class MImageContent(MessageContentBase): + msgtype = 'm.image' + info: ImageInfo + url: Optional[str] = None + file: Optional[EncryptedFile] = None + + +@dataclass +class MFileContent(MessageContentBase): + msgtype = 'm.file' + filename: str + info: FileInfo + url: Optional[str] = None + file: Optional[EncryptedFile] = None + + +@dataclass +class MAudioContent(MessageContentBase): + msgtype = 'm.audio' + info: AudioInfo + url: Optional[str] = None + file: Optional[EncryptedFile] = None + + +@dataclass +class MLocationContent(MessageContentBase): + msgtype = 'm.location' + geo_uri: str + info: LocationInfo + + +@dataclass +class MVideoContent(MessageContentBase): + msgtype = 'm.video' + info: VideoInfo + url: Optional[str] = None + file: Optional[EncryptedFile] = None + + +@dataclass +class PresenceContent(ContentBase): + presence: str + last_active_ago: int + currently_active: bool + avatar_url: Optional[str] = None + displayname: Optional[str] = None + status_message: Optional[str] = None + + +@dataclass +class MRoomAliasesContent(ContentBase): + aliases: List[str] + + +@dataclass +class MRoomCanonicalAliasContent(ContentBase): + alias: str + + +@dataclass +class MRoomCreateContent(ContentBase): + creator: str + room_version: Optional[str] = '1' + m_federate: Optional[bool] = True + predecessor: Optional[PreviousRoom] = None + + +@dataclass +class MRoomJoinRulesContent(ContentBase): + join_rule: str + + +@dataclass +class MRoomMemberContent(ContentBase): + membership: str + is_direct: bool + third_party_invite: Optional[Invite] = None + avatar_url: Optional[str] = None + displayname: str = None + + +@dataclass +class MRoomPowerLevelsContent(ContentBase): + ban: int = 50 + events: Dict[str, int] = field(default_factory=dict) + events_default: int = 0 + invite: int = 50 + kick: int = 50 + redact: int = 50 + state_default: int = 50 + users: Dict[str, int] = field(default_factory=dict) + users_default: int = 0 + notifications: Dict[str, int] = field(default={'room': 50}) + + +@dataclass +class MRoomRedactionContent(ContentBase): + reason: str diff --git a/lib/events.py b/lib/events.py index 119d0cb..bc0296b 100644 --- a/lib/events.py +++ b/lib/events.py @@ -1 +1,39 @@ -# TODO Add Event classes +from dataclasses import dataclass +from typing import Optional, List + +from .room import Room +from .content import ContentBase + + +@dataclass +class EventBase: + content: ContentBase + type: str + sender: str + + +@dataclass +class UnsignedData: + age: int + redacted_because: Optional[EventBase] = None + transaction_id: Optional[str] = None + invite_room_state: Optional[List[EventBase]] = None + + +@dataclass +class RoomEvent(EventBase): + event_id: str + origin_server_id: int + unsigned: UnsignedData + room: Room + + +@dataclass +class StateEvent(RoomEvent): + state_key: str + prev_content: Optional[EventBase] = None + + +@dataclass +class RedactionEvent(RoomEvent): + redacts: EventBase diff --git a/lib/room.py b/lib/room.py index 3c27e74..2646eeb 100644 --- a/lib/room.py +++ b/lib/room.py @@ -1 +1,6 @@ # TODO Add Room class + + +class Room: + def __init__(self, room_id: str): + self.id = room_id diff --git a/lib/utils.py b/lib/utils.py new file mode 100644 index 0000000..655b7fe --- /dev/null +++ b/lib/utils.py @@ -0,0 +1,85 @@ +from dataclasses import dataclass +from typing import Optional, List, Dict + + +@dataclass +class JSONWebKey: + key_opts: List[str] + k: str + ext: bool = True + alg: str = 'A256CTR' + kty: str = 'oct' + + +@dataclass +class EncryptedFile: + url: str + key: JSONWebKey + iv: str + hashes: Dict[str, str] + v: str = 'v2' + + +@dataclass +class ImageInfoBase: + h: int + w: int + mimetype: str + size: int + + +@dataclass +class ImageInfo(ImageInfoBase): + thumbnail_info: ImageInfoBase + thumbnail_url: Optional[str] = None + thumbnail_file: Optional[EncryptedFile] = None + + +@dataclass +class FileInfo: + mimetype: str + size: int + thumbnail_info: ImageInfoBase + thumbnail_url: Optional[str] = None + thumbnail_file: Optional[EncryptedFile] = None + + +@dataclass +class AudioInfo: + duration: int + mimetype: str + size: int + + +@dataclass +class LocationInfo: + thumbnail_info: ImageInfoBase + thumbnail_url: Optional[str] = None + thumbnail_file: Optional[EncryptedFile] = None + + +@dataclass +class VideoInfo(ImageInfoBase): + duration: int + thumbnail_info: ImageInfoBase + thumbnail_url: Optional[str] = None + thumbnail_file: Optional[EncryptedFile] = None + + +@dataclass +class PreviousRoom: + room_id: str + event_id: str + + +@dataclass +class Signed: + mxid: str + signatures: Dict[str, Dict[str, str]] + token: str + + +@dataclass +class Invite: + display_name: str + signed: Signed