Skip to content

Commit

Permalink
Add logic and abstact method for search members endpoint (#350)
Browse files Browse the repository at this point in the history
  • Loading branch information
FasterSpeeding authored Nov 15, 2020
1 parent a93f925 commit 5a2c071
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 0 deletions.
46 changes: 46 additions & 0 deletions hikari/api/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3606,6 +3606,52 @@ def fetch_members(
itself will not raise anything.
"""

@abc.abstractmethod
async def search_members(
self,
guild: snowflakes.SnowflakeishOr[guilds.PartialGuild],
name: str,
) -> typing.Sequence[guilds.Member]:
"""Search the members in a guild by nickname and username.
Parameters
----------
guild : hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild]
The object or ID of the guild to search members in.
name : str
The query to match username(s) and nickname(s) against.
Returns
-------
typing.Sequence[hikari.guilds.Member]
A sequence of the members who matched the provided `name`.
Raises
------
hikari.errors.UnauthorizedError
If you are unauthorized to make the request (invalid/missing token).
hikari.errors.NotFoundError
If the guild is not found.
hikari.errors.RateLimitTooLongError
Raised in the event that a rate limit occurs that is
longer than `max_rate_limit` when making a request.
hikari.errors.RateLimitedError
Usually, Hikari will handle and retry on hitting
rate-limits automatically. This includes most bucket-specific
rate-limits and global rate-limits. In some rare edge cases,
however, Discord implements other undocumented rules for
rate-limiting, such as limits per attribute. These cannot be
detected or handled normally by Hikari due to their undocumented
nature, and will trigger this exception if they occur.
hikari.errors.InternalServerError
If an internal error occurs on Discord while handling the request.
!!! note
Unlike `RESTClient.fetch_members` this endpoint isn't paginated and
therefore will return all the members in one go rather than needing
to be asynchronously iterated over.
"""

@abc.abstractmethod
async def edit_member(
self,
Expand Down
15 changes: 15 additions & 0 deletions hikari/impl/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2000,6 +2000,21 @@ def fetch_members(
entity_factory=self._entity_factory, request_call=self._request, guild=guild
)

async def search_members(
self,
guild: snowflakes.SnowflakeishOr[guilds.PartialGuild],
name: str,
) -> typing.Sequence[guilds.Member]:
route = routes.GET_GUILD_MEMBERS_SEARCH.compile(guild=guild)
query = data_binding.StringMapBuilder()
query.put("query", name)
query.put("limit", 1000)
raw_response = await self._request(route, query=query)
response = typing.cast(data_binding.JSONArray, raw_response)
return data_binding.cast_json_array(
response, self._entity_factory.deserialize_member, guild_id=snowflakes.Snowflake(guild)
)

async def edit_member(
self,
guild: snowflakes.SnowflakeishOr[guilds.PartialGuild],
Expand Down
2 changes: 2 additions & 0 deletions hikari/internal/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,8 @@ def compile_to_file(
GET_GUILD_MEMBERS: typing.Final[Route] = Route(GET, "/guilds/{guild}/members")
DELETE_GUILD_MEMBER: typing.Final[Route] = Route(DELETE, "/guilds/{guild}/members/{user}")

GET_GUILD_MEMBERS_SEARCH: typing.Final[Route] = Route(GET, "/guilds/{guild}/members/search")

PUT_GUILD_MEMBER_ROLE: typing.Final[Route] = Route(PUT, "/guilds/{guild}/members/{user}/roles/{role}")
DELETE_GUILD_MEMBER_ROLE: typing.Final[Route] = Route(DELETE, "/guilds/{guild}/members/{user}/roles/{role}")

Expand Down
11 changes: 11 additions & 0 deletions tests/hikari/impl/test_rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2244,6 +2244,17 @@ async def test_fetch_member(self, rest_client):
rest_client._request.assert_awaited_once_with(expected_route)
rest_client._entity_factory.deserialize_member.assert_called_once_with({"id": "789"}, guild_id=123)

async def test_search_members(self, rest_client):
member = StubModel(645234123)
expected_route = routes.GET_GUILD_MEMBERS_SEARCH.compile(guild=645234123)
expected_query = {"query": "a name", "limit": "1000"}
rest_client._request = mock.AsyncMock(return_value=[{"id": "764435"}])
rest_client._entity_factory.deserialize_member = mock.Mock(return_value=member)

assert await rest_client.search_members(StubModel(645234123), "a name") == [member]
rest_client._entity_factory.deserialize_member.assert_called_once_with({"id": "764435"}, guild_id=645234123)
rest_client._request.assert_awaited_once_with(expected_route, query=expected_query)

async def test_edit_member(self, rest_client):
expected_route = routes.PATCH_GUILD_MEMBER.compile(guild=123, user=456)
expected_json = {"nick": "test", "roles": ["654", "321"], "mute": True, "deaf": False, "channel_id": "987"}
Expand Down

0 comments on commit 5a2c071

Please sign in to comment.