188 lines
6.8 KiB
Python
188 lines
6.8 KiB
Python
# Copyright (c) 2022 Tulir Asokan
|
|
#
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from mautrix.api import Method, Path
|
|
from mautrix.errors import MatrixResponseError, MNotFound
|
|
from mautrix.types import ContentURI, Member, SerializerError, User, UserID, UserSearchResults
|
|
|
|
from .base import BaseClientAPI
|
|
|
|
|
|
class UserDataMethods(BaseClientAPI):
|
|
"""
|
|
Methods in section 10 User Data of the spec. These methods are used for setting and getting user
|
|
metadata and searching for users.
|
|
|
|
See also: `API reference <https://matrix.org/docs/spec/client_server/r0.4.0.html#user-data>`__
|
|
"""
|
|
|
|
# region 10.1 User Directory
|
|
# API reference: https://matrix.org/docs/spec/client_server/r0.4.0.html#user-directory
|
|
|
|
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
|
|
|
|
# endregion
|
|
# region 10.2 Profiles
|
|
# API reference: https://matrix.org/docs/spec/client_server/r0.4.0.html#profiles
|
|
|
|
async def set_displayname(self, displayname: str, check_current: bool = True) -> None:
|
|
"""
|
|
Set the display name of the current user.
|
|
|
|
See also: `API reference <https://matrix.org/docs/spec/client_server/r0.4.0.html#put-matrix-client-r0-profile-userid-displayname>`__
|
|
|
|
Args:
|
|
displayname: The new display name for the user.
|
|
check_current: Whether or not to check if the displayname is already set.
|
|
"""
|
|
if check_current and await self.get_displayname(self.mxid) == displayname:
|
|
return
|
|
await self.api.request(
|
|
Method.PUT,
|
|
Path.v3.profile[self.mxid].displayname,
|
|
{
|
|
"displayname": displayname,
|
|
},
|
|
)
|
|
|
|
async def get_displayname(self, user_id: UserID) -> str | None:
|
|
"""
|
|
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.
|
|
"""
|
|
try:
|
|
content = await self.api.request(Method.GET, Path.v3.profile[user_id].displayname)
|
|
except MNotFound:
|
|
return None
|
|
try:
|
|
return content["displayname"]
|
|
except KeyError:
|
|
return None
|
|
|
|
async def set_avatar_url(self, avatar_url: ContentURI, check_current: bool = True) -> None:
|
|
"""
|
|
Set the avatar of the current user.
|
|
|
|
See also: `API reference <https://matrix.org/docs/spec/client_server/r0.4.0.html#put-matrix-client-r0-profile-userid-avatar-url>`__
|
|
|
|
Args:
|
|
avatar_url: The ``mxc://`` URI to the new avatar.
|
|
check_current: Whether or not to check if the avatar is already set.
|
|
"""
|
|
if check_current and await self.get_avatar_url(self.mxid) == avatar_url:
|
|
return
|
|
await self.api.request(
|
|
Method.PUT,
|
|
Path.v3.profile[self.mxid].avatar_url,
|
|
{
|
|
"avatar_url": avatar_url,
|
|
},
|
|
)
|
|
|
|
async def get_avatar_url(self, user_id: UserID) -> ContentURI | None:
|
|
"""
|
|
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.
|
|
"""
|
|
try:
|
|
content = await self.api.request(Method.GET, Path.v3.profile[user_id].avatar_url)
|
|
except MNotFound:
|
|
return None
|
|
try:
|
|
return content["avatar_url"]
|
|
except KeyError:
|
|
return None
|
|
|
|
async def get_profile(self, user_id: UserID) -> 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.v3.profile[user_id])
|
|
try:
|
|
return Member.deserialize(content)
|
|
except SerializerError as e:
|
|
raise MatrixResponseError("Invalid member in response") from e
|
|
|
|
# endregion
|
|
|
|
# region Beeper Custom Fields API
|
|
|
|
async def beeper_update_profile(self, custom_fields: dict[str, Any]) -> None:
|
|
"""
|
|
Set custom fields on the user's profile. Only works on Hungryserv.
|
|
|
|
Args:
|
|
custom_fields: A dictionary of fields to set in the custom content of the profile.
|
|
"""
|
|
await self.api.request(Method.PATCH, Path.v3.profile[self.mxid], custom_fields)
|
|
|
|
# endregion
|