Repository: hikari-py/hikari
Pull request #955 (2022-01-09 16:33:56)

Implement fetch my member
### Summary
Implement fetch my member

### Checklist
<!-- Make sure to tick all the following boxes by putting an `x` in between (like this `[x]`) -->
- [ ] I have run `nox` and all the pipelines have passed.
- [ ] I have made unittests according to the code I have added/modified/deleted.

### Related issues
<!--
To mention an issue use `#issue-id` and to mention a merge request use `!merge-request-id`
To close/fix an issue use `Close #issue-id` or `Fix #issue-id` (depending on the merge request)
-->



Patch:
diff --git a/changes/955.feature.md b/changes/955.feature.md
new file mode 100644
index 00000000..6caee945
--- /dev/null
+++ b/changes/955.feature.md
@@ -0,0 +1,1 @@
+Added support for GET /users/@me/guilds/{guild}/member
diff --git a/changes/960.feature.md b/changes/960.feature.md
new file mode 100644
index 00000000..bc9ce30e
--- /dev/null
+++ b/changes/960.feature.md
@@ -0,0 +1,1 @@
+Add new presence activity flags.
diff --git a/dev-requirements.txt b/dev-requirements.txt
index 6d4c46dc..777ccc56 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -28,7 +28,7 @@ sphobjinv==2.1
 # TYPE CHECKING #
 #################
 
-mypy==0.930
+mypy==0.931
 pyright==0.0.13
 
 #######################
diff --git a/hikari/api/interaction_server.py b/hikari/api/interaction_server.py
index 2fc389c7..d4d17b68 100644
--- a/hikari/api/interaction_server.py
+++ b/hikari/api/interaction_server.py
@@ -195,18 +195,6 @@ def set_listener(
     ) -> None:
         ...
 
-    @typing.overload
-    @abc.abstractmethod
-    def set_listener(
-        self,
-        interaction_type: typing.Type[_InteractionT_co],
-        listener: typing.Optional[ListenerT[_InteractionT_co, special_endpoints.InteractionResponseBuilder]],
-        /,
-        *,
-        replace: bool = False,
-    ) -> None:
-        ...
-
     @abc.abstractmethod
     def set_listener(
         self,
diff --git a/hikari/api/rest.py b/hikari/api/rest.py
index 52305954..1072c3a1 100644
--- a/hikari/api/rest.py
+++ b/hikari/api/rest.py
@@ -4894,6 +4894,40 @@ def fetch_members(
             doesn't require any intents.
         """
 
+    @abc.abstractmethod
+    async def fetch_my_member(self, guild: snowflakes.SnowflakeishOr[guilds.PartialGuild]) -> guilds.Member:
+        """Fetch the Oauth token's associated member in a guild.
+
+        !!! warning
+            This endpoint can only be used with a Bearer token. Using this
+            with a Bot token will result in a `hikari.errors.UnauthorizedError`.
+
+        Returns
+        -------
+        hikari.guilds.Member
+            The associated guild member.
+
+        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.
+        """
+
     @abc.abstractmethod
     async def search_members(
         self,
diff --git a/hikari/applications.py b/hikari/applications.py
index 6566d344..67a7361e 100644
--- a/hikari/applications.py
+++ b/hikari/applications.py
@@ -221,6 +221,9 @@ class OAuth2Scope(str, enums.Enum):
     This is used during authorization code grants.
     """
 
+    GUILDS_MEMBERS_READ = "guilds.members.read"
+    """Used to read the current user's guild members."""
+
 
 @typing.final
 class ConnectionVisibility(int, enums.Enum):
diff --git a/hikari/impl/interaction_server.py b/hikari/impl/interaction_server.py
index e72ee330..8863624c 100644
--- a/hikari/impl/interaction_server.py
+++ b/hikari/impl/interaction_server.py
@@ -538,19 +538,6 @@ def set_listener(
     ) -> None:
         ...
 
-    @typing.overload
-    def set_listener(
-        self,
-        interaction_type: typing.Type[_InteractionT_co],
-        listener: typing.Optional[
-            interaction_server.ListenerT[_InteractionT_co, special_endpoints.InteractionResponseBuilder]
-        ],
-        /,
-        *,
-        replace: bool = False,
-    ) -> None:
-        ...
-
     def set_listener(
         self,
         interaction_type: typing.Type[_InteractionT_co],
diff --git a/hikari/impl/rest.py b/hikari/impl/rest.py
index c8d5c802..1e3f0d00 100644
--- a/hikari/impl/rest.py
+++ b/hikari/impl/rest.py
@@ -2678,6 +2678,12 @@ def fetch_members(
             entity_factory=self._entity_factory, request_call=self._request, guild=guild
         )
 
+    async def fetch_my_member(self, guild: snowflakes.SnowflakeishOr[guilds.PartialGuild]) -> guilds.Member:
+        route = routes.GET_MY_GUILD_MEMBER.compile(guild=guild)
+        response = await self._request(route)
+        assert isinstance(response, dict)
+        return self._entity_factory.deserialize_member(response, guild_id=snowflakes.Snowflake(guild))
+
     async def search_members(
         self,
         guild: snowflakes.SnowflakeishOr[guilds.PartialGuild],
diff --git a/hikari/impl/rest_bot.py b/hikari/impl/rest_bot.py
index 299c7164..f3dda104 100644
--- a/hikari/impl/rest_bot.py
+++ b/hikari/impl/rest_bot.py
@@ -624,19 +624,6 @@ def set_listener(
     ) -> None:
         ...
 
-    @typing.overload
-    def set_listener(
-        self,
-        interaction_type: typing.Type[_InteractionT_co],
-        listener: typing.Optional[
-            interaction_server_.ListenerT[_InteractionT_co, special_endpoints.InteractionResponseBuilder]
-        ],
-        /,
-        *,
-        replace: bool = False,
-    ) -> None:
-        ...
-
     def set_listener(
         self,
         interaction_type: typing.Type[_InteractionT_co],
@@ -647,4 +634,4 @@ def set_listener(
         *,
         replace: bool = False,
     ) -> None:
-        self._server.set_listener(interaction_type, listener, replace=replace)
+        self._server.set_listener(interaction_type, listener, replace=replace)  # type: ignore
diff --git a/hikari/internal/routes.py b/hikari/internal/routes.py
index b3cfd8dc..d803993e 100644
--- a/hikari/internal/routes.py
+++ b/hikari/internal/routes.py
@@ -438,6 +438,7 @@ def compile_to_file(
 # @me
 POST_MY_CHANNELS: typing.Final[Route] = Route(POST, "/users/@me/channels")
 GET_MY_CONNECTIONS: typing.Final[Route] = Route(GET, "/users/@me/connections")  # OAuth2 only
+GET_MY_GUILD_MEMBER: typing.Final[Route] = Route(GET, "/users/@me/guilds/{guild}/member")  # OAuth2 only
 DELETE_MY_GUILD: typing.Final[Route] = Route(DELETE, "/users/@me/guilds/{guild}")
 
 GET_MY_GUILDS: typing.Final[Route] = Route(GET, "/users/@me/guilds")
diff --git a/hikari/presences.py b/hikari/presences.py
index 73192e78..b6f72c49 100644
--- a/hikari/presences.py
+++ b/hikari/presences.py
@@ -176,6 +176,15 @@ class ActivityFlag(enums.Flag):
     PLAY = 1 << 5
     """Play"""
 
+    PARTY_PRIVACY_FRIENDS = 1 << 6
+    """Party privacy: friends only."""
+
+    PARTY_PRIVACY_VOICE_CHANNEL = 1 << 7
+    """Party prvacy: voice channel only."""
+
+    EMBEDDED = 1 << 8
+    """An activity that's embedded into a voice channel."""
+
 
 # TODO: add strict type checking to gateway for this type in an invariant way.
 @attr_extensions.with_copy


Test patch:
diff --git a/tests/hikari/impl/test_rest.py b/tests/hikari/impl/test_rest.py
index 421d7d90..106671c8 100644
--- a/tests/hikari/impl/test_rest.py
+++ b/tests/hikari/impl/test_rest.py
@@ -3438,6 +3438,18 @@ 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_fetch_my_member(self, rest_client) -> guilds.Member:
+        expected_route = routes.GET_MY_GUILD_MEMBER.compile(guild=45123)
+        rest_client._request = mock.AsyncMock(return_value={"id": "595995"})
+
+        result = await rest_client.fetch_my_member(StubModel(45123))
+
+        assert result is rest_client._entity_factory.deserialize_member.return_value
+        rest_client._request.assert_awaited_once_with(expected_route)
+        rest_client._entity_factory.deserialize_member.assert_called_once_with(
+            rest_client._request.return_value, guild_id=45123
+        )
+
     async def test_search_members(self, rest_client):
         member = StubModel(645234123)
         expected_route = routes.GET_GUILD_MEMBERS_SEARCH.compile(guild=645234123)