Example #1
0
    async def get_joined_members(self,
                                 room_id: RoomID) -> Dict[UserID, Member]:
        """
        Get a user ID -> member info map for a room. The current user must be in the room for it to
        work, unless it is an Application Service in which case any of the AS's users must be in the
        room. This API is primarily for Application Services and should be faster to respond than
        `/members`_ as it can be implemented more efficiently on the server.
        See also: `/joined_members API reference`_

        Args:
            room_id: The ID of the room to get the members of.

        Returns:
            A dictionary from user IDs to Member info objects.

        .. _/joined_members API reference:
            https://matrix.org/docs/spec/client_server/r0.5.0#get-matrix-client-r0-rooms-roomid-joined-members
        .. _/members:
            https://matrix.org/docs/spec/client_server/r0.5.0#get-matrix-client-r0-rooms-roomid-members
        """
        content = await self.api.request(Method.GET,
                                         Path.rooms[room_id].joined_members)
        try:
            return {
                user_id: Member(membership=Membership.JOIN,
                                displayname=member.get("display_name", ""),
                                avatar_url=member.get("avatar_url", ""))
                for user_id, member in content["joined"].items()
            }
        except KeyError:
            raise MatrixResponseError("`joined` not in response.")
        except SerializerError as e:
            raise MatrixResponseError(
                "Invalid member objects in response") from e
Example #2
0
    async def get_messages(
            self,
            room_id: RoomID,
            direction: PaginationDirection,
            from_token: SyncToken,
            to_token: Optional[SyncToken] = None,
            limit: Optional[int] = None,
            filter_json: Optional[str] = None) -> PaginatedMessages:
        """
        Get a list of message and state events for a room. Pagination parameters are used to
        paginate history in the room. See also: `/messages API reference`_

        Args:
            room_id: The ID of the room to get events from.
            direction: The direction to return events from.
            from_token: The token to start returning events from. This token can be obtained from a
                ``prev_batch`` token returned for each room by the `sync endpoint`_, or from a
                ``start`` or ``end`` token returned by a previous request to this endpoint.
            to_token: The token to stop returning events at.
            limit: The maximum number of events to return. Defaults to 10.
            filter_json: A JSON RoomEventFilter_ to filter returned events with.

        Returns:

        .. _RoomEventFilter:
            https://matrix.org/docs/spec/client_server/r0.5.0#filtering
        .. _sync endpoint:
            https://matrix.org/docs/spec/client_server/r0.5.0#get-matrix-client-r0-sync
        .. _/messages API reference:
            https://matrix.org/docs/spec/client_server/r0.5.0#get-matrix-client-r0-rooms-roomid-messages
        """
        query_params = {
            "from": from_token,
            "dir": direction.value,
        }
        if to_token:
            query_params["to"] = to_token
        if limit:
            query_params["limit"] = str(limit)
        if filter:
            query_params["filter"] = filter_json
        content = await self.api.request(Method.GET,
                                         Path.rooms[room_id].messages,
                                         query_params=query_params)
        try:
            return PaginatedMessages(
                content["start"], content["end"],
                [Event.deserialize(event) for event in content["chunk"]])
        except KeyError:
            if "start" not in content:
                raise MatrixResponseError("`start` not in response.")
            elif "end" not in content:
                raise MatrixResponseError("`start` not in response.")
            raise MatrixResponseError("`content` not in response.")
        except SerializerError as e:
            raise MatrixResponseError("Invalid events in response") from e
Example #3
0
    async def get_members(
        self,
        room_id: RoomID,
        at: SyncToken | None = None,
        membership: Membership | None = None,
        not_membership: Membership | None = None,
    ) -> list[StateEvent]:
        """
        Get the list of members for a room.

        See also: `API reference <https://spec.matrix.org/v1.1/client-server-api/#get_matrixclientv3roomsroomidmembers>`__

        Args:
            room_id: The ID of the room to get the member events for.
            at: The point in time (pagination token) to return members for in the room. This token
                can be obtained from a ``prev_batch`` token returned for each room by the sync API.
                Defaults to the current state of the room, as determined by the server.
            membership: The kind of membership to filter for. Defaults to no filtering if
                unspecified. When specified alongside ``not_membership``, the two parameters create
                an 'or' condition: either the ``membership`` is the same as membership or is not the
                same as ``not_membership``.
            not_membership: The kind of membership to exclude from the results. Defaults to no
                filtering if unspecified.

        Returns:
            A list of most recent member events for each user.
        """
        query = {}
        if at:
            query["at"] = at
        if membership:
            query["membership"] = membership.value
        if not_membership:
            query["not_membership"] = not_membership.value
        content = await self.api.request(
            Method.GET,
            Path.v3.rooms[room_id].members,
            query_params=query,
            metrics_method="getMembers",
        )
        try:
            return [
                StateEvent.deserialize(event) for event in content["chunk"]
            ]
        except KeyError:
            raise MatrixResponseError("`chunk` not in response.")
        except SerializerError as e:
            raise MatrixResponseError(
                "Invalid state events in response") from e
Example #4
0
    async def get_state_event(
        self,
        room_id: RoomID,
        event_type: EventType,
        state_key: str = "",
    ) -> StateEventContent:
        """
        Looks up the contents of a state event in a room. If the user is joined to the room then the
        state is taken from the current state of the room. If the user has left the room then the
        state is taken from the state of the room when they left.

        See also: `API reference <https://spec.matrix.org/v1.1/client-server-api/#get_matrixclientv3roomsroomidstateeventtypestatekey>`__

        Args:
            room_id: The ID of the room to look up the state in.
            event_type: The type of state to look up.
            state_key: The key of the state to look up. Defaults to empty string.

        Returns:
            The state event.
        """
        content = await self.api.request(
            Method.GET,
            Path.v3.rooms[room_id].state[event_type][state_key],
            metrics_method="getStateEvent",
        )
        content["__mautrix_event_type"] = event_type
        try:
            return StateEvent.deserialize_content(content)
        except SerializerError as e:
            raise MatrixResponseError("Invalid state event in response") from e
Example #5
0
    async def get_state_event(
            self,
            room_id: RoomID,
            event_type: EventType,
            state_key: Optional[str] = None) -> StateEventContent:
        """
        Looks up the contents of a state event in a room. If the user is joined to the room then the
        state is taken from the current state of the room. If the user has left the room then the
        state is taken from the state of the room when they left.
        See also: `GET /state/{eventType}/{stateKey} API reference`_

        Args:
            room_id: The ID of the room to look up the state in.
            event_type: The type of state to look up.
            state_key: The key of the state to look up. Defaults to empty string.

        Returns:
            The state event.

        .. _GET /state/{eventType}/{stateKey} API reference:
            https://matrix.org/docs/spec/client_server/r0.5.0#get-matrix-client-r0-rooms-roomid-state-eventtype-statekey
        """
        content = await self.api.request(
            Method.GET, Path.rooms[room_id].state[event_type][state_key])
        try:
            return state_event_content_map[event_type].deserialize(content)
        except KeyError:
            return Obj(**content)
        except SerializerError as e:
            raise MatrixResponseError("Invalid state event in response") from e
Example #6
0
 async def get_joined_rooms(self) -> List[RoomID]:
     """Get the list of rooms the user is in."""
     content = await self.api.request(Method.GET, Path.joined_rooms)
     try:
         return content["joined_rooms"]
     except KeyError:
         raise MatrixResponseError("`joined_rooms` not in response.")
Example #7
0
    async def send_message_event(self, room_id: RoomID, event_type: EventType,
                                 content: EventContent, **kwargs) -> EventID:
        """
        Send a message event to a room. Message events allow access to historical events and
        pagination, making them suited for "once-off" activity in a room.
        See also: `/send API reference`_

        Args:
            room_id: The ID of the room to send the message to.
            event_type: The type of message to send.
            content: The content to send.
            **kwargs: Optional parameters to pass to the :meth:`HTTPAPI.request` method. Used by
                :class:`IntentAPI` to pass the timestamp massaging field to
                :meth:`AppServiceAPI.request`.

        Returns:
            The ID of the event that was sent.

        .. _/send API reference:
            https://matrix.org/docs/spec/client_server/r0.5.0#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
        """
        if not room_id:
            raise ValueError("Room ID not given")
        elif not event_type:
            raise ValueError("Event type not given")
        url = Path.rooms[room_id].send[event_type][self.api.get_txn_id()]
        content = content.serialize() if isinstance(content,
                                                    Serializable) else content
        resp = await self.api.request(Method.PUT, url, content, **kwargs)
        try:
            return resp["event_id"]
        except KeyError:
            raise MatrixResponseError("`event_id` not in response.")
Example #8
0
    async def send_state_event(self,
                               room_id: RoomID,
                               event_type: EventType,
                               content: StateEventContent,
                               state_key: Optional[str] = "",
                               **kwargs) -> EventID:
        """
        Send a state event to a room. State events with the same ``room_id``, ``event_type`` and
        ``state_key`` will be overridden.
        See also: `PUT /state/{eventType}/{stateKey} API reference`_

        Args:
            room_id: The ID of the room to set the state in.
            event_type: The type of state to send.
            content: The content to send.
            state_key: The key for the state to send. Defaults to empty string.
            **kwargs: Optional parameters to pass to the :meth:`HTTPAPI.request` method. Used by
                :class:`IntentAPI` to pass the timestamp massaging field to
                :meth:`AppServiceAPI.request`.

        Returns:
            The ID of the event that was sent.

        .. _PUT /state/{eventType}/{stateKey} API reference:
            https://matrix.org/docs/spec/client_server/r0.5.0#put-matrix-client-r0-rooms-roomid-state-eventtype-statekey
        """
        content = content.serialize() if isinstance(content,
                                                    Serializable) else content
        resp = await self.api.request(
            Method.PUT, Path.rooms[room_id].state[event_type][state_key],
            content, **kwargs)
        try:
            return resp["event_id"]
        except KeyError:
            raise MatrixResponseError("`event_id` not in response.")
Example #9
0
    async def search_users(self,
                           search_query: str,
                           limit: int | None = 10) -> UserSearchResults:
        """
        Performs a search for users on the homeserver. The homeserver may determine which subset of
        users are searched, however the homeserver MUST at a minimum consider the users the
        requesting user shares a room with and those who reside in public rooms (known to the
        homeserver). The search MUST consider local users to the homeserver, and SHOULD query remote
        users as part of the search.

        The search is performed case-insensitively on user IDs and display names preferably using a
        collation determined based upon the Accept-Language header provided in the request, if
        present.

        See also: `API reference <https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-user-directory-search>`__

        Args:
            search_query: The query to search for.
            limit: The maximum number of results to return.

        Returns:
            The results of the search and whether or not the results were limited.
        """
        content = await self.api.request(
            Method.POST,
            Path.v3.user_directory.search,
            {
                "search_term": search_query,
                "limit": limit,
            },
        )
        try:
            return UserSearchResults(
                [User.deserialize(user) for user in content["results"]],
                content["limited"])
        except SerializerError as e:
            raise MatrixResponseError("Invalid user in search results") from e
        except KeyError:
            if "results" not in content:
                raise MatrixResponseError("`results` not in content.")
            elif "limited" not in content:
                raise MatrixResponseError("`limited` not in content.")
            raise
Example #10
0
    async def whoami(self) -> UserID:
        """
        Get information about the current user.

        Returns:
            The user ID of the current user.
        """
        resp = await self.api.request(Method.GET, Path.account.whoami)
        try:
            return resp["user_id"]
        except KeyError:
            raise MatrixResponseError("`user_id` not in response.")
Example #11
0
    async def join_room(self,
                        room_id_or_alias: Union[RoomID, RoomAlias],
                        servers: List[str] = None,
                        third_party_signed: JSON = None,
                        max_retries: int = 4) -> RoomID:
        """
        Start participating in a room, i.e. join it by its ID or alias, with an optional list of
        servers to ask about the ID from.

        See also: `API reference <https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-join-roomidoralias>`__

        Args:
            room_id_or_alias: The ID of the room to join, or an alias pointing to the room.
            servers: A list of servers to ask about the room ID to join. Not applicable for aliases,
                as aliases already contain the necessary server information.
            third_party_signed: A signature of an ``m.third_party_invite`` token to prove that this
                user owns a third party identity which has been invited to the room.
            max_retries: The maximum number of retries. Used to circumvent a Synapse bug with
                accepting invites over federation. 0 means only one join call will be attempted.
                See: `matrix-org/synapse#2807 <https://github.com/matrix-org/synapse/issues/2807>`__

        Returns:
            The ID of the room the user joined.
        """
        max_retries = max(0, max_retries)
        tries = 0
        content = {
            "third_party_signed": third_party_signed
        } if third_party_signed is not None else None
        query_params = CIMultiDict()
        for server_name in (servers or []):
            query_params.add("server_name", server_name)
        while tries <= max_retries:
            try:
                content = await self.api.request(Method.POST,
                                                 Path.join[room_id_or_alias],
                                                 content=content,
                                                 query_params=query_params)
                break
            except MatrixRequestError:
                tries += 1
                if tries <= max_retries:
                    wait = tries * 10
                    self.log.exception(
                        f"Failed to join room {room_id_or_alias}, retrying in {wait} seconds..."
                    )
                    await asyncio.sleep(wait, loop=self.loop)
                else:
                    raise
        try:
            return content["room_id"]
        except KeyError:
            raise MatrixResponseError("`room_id` not in response.")
Example #12
0
    async def upload_keys(
        self,
        one_time_keys: dict[str, Any] | None = None,
        device_keys: dict[str, Any] | None = None,
    ) -> dict[EncryptionKeyAlgorithm, int]:
        """
        Publishes end-to-end encryption keys for the device.

        See also: `API reference <https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-keys-upload>`__

        Args:
            one_time_keys: One-time public keys for "pre-key" messages. The names of the properties
                should be in the format ``<algorithm>:<key_id>``. The format of the key is
                determined by the key algorithm.
            device_keys: Identity keys for the device. May be absent if no new identity keys are
                required.

        Returns:
            For each key algorithm, the number of unclaimed one-time keys of that type currently
            held on the server for this device.
        """
        data = {}
        if device_keys:
            data["device_keys"] = device_keys
        if one_time_keys:
            data["one_time_keys"] = one_time_keys
        resp = await self.api.request(Method.POST, Path.v3.keys.upload, data)
        try:
            return {
                EncryptionKeyAlgorithm.deserialize(alg): count
                for alg, count in resp["one_time_key_counts"].items()
            }
        except KeyError as e:
            raise MatrixResponseError(
                "`one_time_key_counts` not in response.") from e
        except AttributeError as e:
            raise MatrixResponseError(
                "Invalid `one_time_key_counts` field in response.") from e
Example #13
0
    async def get_room_directory_visibility(
            self, room_id: RoomID) -> RoomDirectoryVisibility:
        """
        Get the visibility of the room on the server's public room directory.

        See also: `API reference <https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-directory-list-room-roomid>`__

        Args:
            room_id: The ID of the room.

        Returns:
            The visibility of the room in the directory.
        """
        resp = await self.api.request(Method.GET,
                                      Path.directory.list.room[room_id])
        try:
            return RoomDirectoryVisibility(resp["visibility"])
        except KeyError:
            raise MatrixResponseError("`visibility` not in response.")
        except ValueError:
            raise MatrixResponseError(
                f"Invalid value for `visibility` in response: {resp['visibility']}"
            )
Example #14
0
    async def get_login_flows(self) -> LoginFlowList:
        """
        Get login flows supported by the homeserver.

        See also: `API reference <https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-login>`__

        Returns:
            The list of login flows that the homeserver supports.
        """
        resp = await self.api.request(Method.GET, Path.v3.login)
        try:
            return LoginFlowList.deserialize(resp)
        except KeyError:
            raise MatrixResponseError("`flows` not in response.")
Example #15
0
    async def unstable_create_mxc(self) -> ContentURI:
        """
        Create a media ID for uploading media to the homeserver. Requires the homeserver to have
        `MSC2246 <https://github.com/matrix-org/matrix-spec-proposals/pull/2246>`__ support.

        Returns:
            The MXC URI that can be used to upload a file to later.

        Raises:
            MatrixResponseError: If the response does not contain a ``content_uri`` field.
        """
        resp = await self.api.request(Method.POST, MediaPath.unstable["fi.mau.msc2246"].create)
        try:
            return resp["content_uri"]
        except KeyError:
            raise MatrixResponseError("`content_uri` not in response.")
Example #16
0
    async def get_profile(self, user_id: str) -> Member:
        """
        Get the combined profile information for a user.

        See also: `API reference <https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-profile-userid>`__

        Args:
            user_id: The ID of the user whose profile to get.

        Returns:
            The profile information of the given user.
        """
        content = await self.api.request(Method.GET, Path.profile[user_id])
        try:
            return Member.deserialize(content)
        except SerializerError as e:
            raise MatrixResponseError("Invalid member in response") from e
Example #17
0
    async def redact(
        self,
        room_id: RoomID,
        event_id: EventID,
        reason: str | None = None,
        extra_content: dict[str, JSON] | None = None,
        **kwargs,
    ) -> EventID:
        """
        Send an event to redact a previous event.

        Redacting an event strips all information out of an event which isn't critical to the
        integrity of the server-side representation of the room.

        This cannot be undone.

        Users may redact their own events, and any user with a power level greater than or equal to
        the redact power level of the room may redact events there.

        See also: `API reference <https://spec.matrix.org/v1.1/client-server-api/#put_matrixclientv3roomsroomidredacteventidtxnid>`__

        Args:
            room_id: The ID of the room the event is in.
            event_id: The ID of the event to redact.
            reason: The reason for the event being redacted.
            extra_content: Extra content for the event.
            **kwargs: Optional parameters to pass to the :meth:`HTTPAPI.request` method. Used by
                :class:`IntentAPI` to pass the timestamp massaging field to
                :meth:`AppServiceAPI.request`.

        Returns:
            The ID of the event that was sent to redact the other event.
        """
        url = Path.v3.rooms[room_id].redact[event_id][self.api.get_txn_id()]
        content = extra_content or {}
        if reason:
            content["reason"] = reason
        resp = await self.api.request(Method.PUT,
                                      url,
                                      content=content,
                                      **kwargs,
                                      metrics_method="redact")
        try:
            return resp["event_id"]
        except KeyError:
            raise MatrixResponseError("`event_id` not in response.")
Example #18
0
    async def get_presence(self, user_id: UserID) -> PresenceEventContent:
        """
        Get the presence info of a user.

        See also: `API reference <https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-presence-list-userid>`__

        Args:
            user_id: The ID of the user whose presence info to get.

        Returns:
            The presence info of the given user.
        """
        content = await self.api.request(Method.GET,
                                         Path.presence[user_id].status)
        try:
            return PresenceEventContent.deserialize(content)
        except SerializerError:
            raise MatrixResponseError("Invalid presence in response")
Example #19
0
    async def get_displayname(self, user_id: str) -> str:
        """
        Get the display name of a user.

        See also: `API reference <https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-profile-userid-displayname>`__

        Args:
            user_id: The ID of the user whose display name to get.

        Returns:
            The display name of the given user.
        """
        content = await self.api.request(Method.GET,
                                         Path.profile[user_id].displayname)
        try:
            return content["displayname"]
        except KeyError:
            raise MatrixResponseError("`displayname` not in response.")
Example #20
0
    async def get_avatar_url(self, user_id: str) -> str:
        """
        Get the avatar URL of a user.

        See also: `API reference <https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-profile-userid-avatar-url>`__

        Args:
            user_id: The ID of the user whose avatar to get.

        Returns:
            The ``mxc://`` URI to the user's avatar.
        """
        content = await self.api.request(Method.GET,
                                         Path.profile[user_id].avatar_url)
        try:
            return content["avatar_url"]
        except KeyError:
            raise MatrixResponseError("`avatar_url` not in response.")
Example #21
0
    async def create_filter(self, filter_params: Filter) -> FilterID:
        """
        Upload a new filter definition to the homeserver.

        See also: `API reference <https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-user-userid-filter>`__

        Args:
            filter_params: The filter data.

        Returns:
            A filter ID that can be used in future requests to refer to the uploaded filter.
        """
        resp = await self.api.request(Method.POST, Path.user[self.mxid].filter,
                                      filter_params.serialize()
                                      if isinstance(filter_params, Serializable) else filter_params)
        try:
            return resp["filter_id"]
        except KeyError:
            raise MatrixResponseError("`filter_id` not in response.")
Example #22
0
    async def send_message_event(
        self,
        room_id: RoomID,
        event_type: EventType,
        content: EventContent,
        txn_id: str | None = None,
        **kwargs,
    ) -> EventID:
        """
        Send a message event to a room. Message events allow access to historical events and
        pagination, making them suited for "once-off" activity in a room.

        See also: `API reference <https://spec.matrix.org/v1.1/client-server-api/#put_matrixclientv3roomsroomidsendeventtypetxnid>`__

        Args:
            room_id: The ID of the room to send the message to.
            event_type: The type of message to send.
            content: The content to send.
            txn_id: The transaction ID to use. If not provided, a random ID will be generated.
            **kwargs: Optional parameters to pass to the :meth:`HTTPAPI.request` method. Used by
                :class:`IntentAPI` to pass the timestamp massaging field to
                :meth:`AppServiceAPI.request`.

        Returns:
            The ID of the event that was sent.
        """
        if not room_id:
            raise ValueError("Room ID not given")
        elif not event_type:
            raise ValueError("Event type not given")
        url = Path.v3.rooms[room_id].send[event_type][txn_id
                                                      or self.api.get_txn_id()]
        content = content.serialize() if isinstance(content,
                                                    Serializable) else content
        resp = await self.api.request(Method.PUT,
                                      url,
                                      content,
                                      **kwargs,
                                      metrics_method="sendMessageEvent")
        try:
            return resp["event_id"]
        except KeyError:
            raise MatrixResponseError("`event_id` not in response.")
Example #23
0
    async def get_state(self, room_id: RoomID) -> List[StateEvent]:
        """
        Get the state events for the current state of a room. See also: `/state API reference`_

        Args:
            room_id: The ID of the room to look up the state for.

        Returns:
            A list of state events with the most recent of each event_type/state_key pair.

        .. _/state API reference:
            https://matrix.org/docs/spec/client_server/r0.5.0#get-matrix-client-r0-rooms-roomid-state
        """
        content = await self.api.request(Method.GET, Path.rooms[room_id].state)
        try:
            return [StateEvent.deserialize(event) for event in content]
        except SerializerError as e:
            raise MatrixResponseError(
                "Invalid state events in response") from e
Example #24
0
    async def get_state(self, room_id: RoomID) -> list[StateEvent]:
        """
        Get the state events for the current state of a room.

        See also: `API reference <https://spec.matrix.org/v1.1/client-server-api/#get_matrixclientv3roomsroomidstate>`__

        Args:
            room_id: The ID of the room to look up the state for.

        Returns:
            A list of state events with the most recent of each event_type/state_key pair.
        """
        content = await self.api.request(Method.GET,
                                         Path.v3.rooms[room_id].state,
                                         metrics_method="getState")
        try:
            return [StateEvent.deserialize(event) for event in content]
        except SerializerError as e:
            raise MatrixResponseError(
                "Invalid state events in response") from e
Example #25
0
    async def upload_media(self,
                           data: Union[bytes, AsyncIterable[bytes]],
                           mime_type: Optional[str] = None,
                           filename: Optional[str] = None,
                           size: Optional[int] = None) -> ContentURI:
        """
        Upload a file to the content repository.

        See also: `API reference <https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-media-r0-upload>`__

        Args:
            data: The data to upload.
            mime_type: The MIME type to send with the upload request.
            filename: The filename to send with the upload request.
            size: The file size to send with the upload request.

        Returns:
            The MXC URI to the uploaded file.

        Raises:
            MatrixResponseError: If the response does not contain a ``content_uri`` field.
        """
        if magic and isinstance(data, bytes):
            mime_type = mime_type or magic.from_buffer(data, mime=True)
        headers = {}
        if mime_type:
            headers["Content-Type"] = mime_type
        if size:
            headers["Content-Length"] = str(size)
        query = {}
        if filename:
            query["filename"] = filename
        resp = await self.api.request(Method.POST,
                                      MediaPath.upload,
                                      content=data,
                                      headers=headers,
                                      query_params=query)
        try:
            return resp["content_uri"]
        except KeyError:
            raise MatrixResponseError("`content_uri` not in response.")
Example #26
0
    async def redact(self,
                     room_id: RoomID,
                     event_id: EventID,
                     reason: Optional[str] = "",
                     **kwargs) -> EventID:
        """
        Send an event to redact a previous event.

        Redacting an event strips all information out of an event which isn't critical to the
        integrity of the server-side representation of the room.

        This cannot be undone.

        Users may redact their own events, and any user with a power level greater than or equal to
        the redact power level of the room may redact events there.

        See also: `/redact API reference`_

        Args:
            room_id: The ID of the room the event is in.
            event_id: The ID of the event to redact.
            reason: The reason for the event being redacted.
            **kwargs: Optional parameters to pass to the :meth:`HTTPAPI.request` method. Used by
                :class:`IntentAPI` to pass the timestamp massaging field to
                :meth:`AppServiceAPI.request`.

        Returns:
            The ID of the event that was sent to redact the other event.

        .. _/redact API reference:
            https://matrix.org/docs/spec/client_server/r0.5.0#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid
        """
        url = Path.rooms[room_id].redact[event_id][self.api.get_txn_id()]
        resp = await self.api.request(Method.PUT,
                                      url,
                                      content={"reason": reason},
                                      **kwargs)
        try:
            return resp["event_id"]
        except KeyError:
            raise MatrixResponseError("`event_id` not in response.")
Example #27
0
    async def get_url_preview(self, url: str, timestamp: int | None = None) -> MXOpenGraph:
        """
        Get information about a URL for a client.

        See also: `API reference <https://spec.matrix.org/v1.2/client-server-api/#get_matrixmediav3preview_url>`__

        Args:
            url: The URL to get a preview of.
            timestamp: The preferred point in time to return a preview for. The server may return a
                newer version if it does not have the requested version available.
        """
        query_params = {"url": url}
        if timestamp is not None:
            query_params["ts"] = timestamp
        content = await self.api.request(
            Method.GET, MediaPath.v3.preview_url, query_params=query_params
        )
        try:
            return MXOpenGraph.deserialize(content)
        except SerializerError as e:
            raise MatrixResponseError("Invalid MXOpenGraph in response.") from e
Example #28
0
    async def get_event(self, room_id: RoomID, event_id: EventID) -> Event:
        """
        Get a single event based on ``room_id``/``event_id``. You must have permission to retrieve
        this event e.g. by being a member in the room for this event.
        See also: `/event/{eventId} API reference`_

        Args:
            room_id: The ID of the room the event is in.
            event_id: The event ID to get.

        Returns:
            The event.

        .. _/event/{eventId} API reference:
            https://matrix.org/docs/spec/client_server/r0.5.0#get-matrix-client-r0-rooms-roomid-event-eventid
        """
        content = await self.api.request(Method.GET,
                                         Path.rooms[room_id].event[event_id])
        try:
            return Event.deserialize(content)
        except SerializerError as e:
            raise MatrixResponseError("Invalid event in response") from e
Example #29
0
    async def get_media_repo_config(self) -> MediaRepoConfig:
        """
        This endpoint allows clients to retrieve the configuration of the content repository, such
        as upload limitations. Clients SHOULD use this as a guide when using content repository
        endpoints. All values are intentionally left optional. Clients SHOULD follow the advice
        given in the field description when the field is not available.

        **NOTE:** Both clients and server administrators should be aware that proxies between the
        client and the server may affect the apparent behaviour of content repository APIs, for
        example, proxies may enforce a lower upload size limit than is advertised by the server on
        this endpoint.

        See also: `API reference <https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-media-r0-config>`__

        Returns:
            The media repository config.
        """
        content = await self.api.request(Method.GET, MediaPath.v3.config)
        try:
            return MediaRepoConfig.deserialize(content)
        except SerializerError as e:
            raise MatrixResponseError("Invalid MediaRepoConfig in response") from e
Example #30
0
    async def send_state_event(
        self,
        room_id: RoomID,
        event_type: EventType,
        content: StateEventContent,
        state_key: str = "",
        **kwargs,
    ) -> EventID:
        """
        Send a state event to a room. State events with the same ``room_id``, ``event_type`` and
        ``state_key`` will be overridden.

        See also: `API reference <https://spec.matrix.org/v1.1/client-server-api/#put_matrixclientv3roomsroomidstateeventtypestatekey>`__

        Args:
            room_id: The ID of the room to set the state in.
            event_type: The type of state to send.
            content: The content to send.
            state_key: The key for the state to send. Defaults to empty string.
            **kwargs: Optional parameters to pass to the :meth:`HTTPAPI.request` method. Used by
                :class:`IntentAPI` to pass the timestamp massaging field to
                :meth:`AppServiceAPI.request`.

        Returns:
            The ID of the event that was sent.
        """
        content = content.serialize() if isinstance(content,
                                                    Serializable) else content
        resp = await self.api.request(
            Method.PUT,
            Path.v3.rooms[room_id].state[event_type][state_key],
            content,
            **kwargs,
            metrics_method="sendStateEvent",
        )
        try:
            return resp["event_id"]
        except KeyError:
            raise MatrixResponseError("`event_id` not in response.")