Skip to content

Commit 32efa3e

Browse files
committed
Fetch Owner User on Bot when login
1 parent ed6d767 commit 32efa3e

File tree

1 file changed

+62
-1
lines changed

1 file changed

+62
-1
lines changed

twitchio/ext/commands/bot.py

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from typing import TYPE_CHECKING, Any, TypeAlias, Unpack
3333

3434
from twitchio.client import Client
35+
from twitchio.user import PartialUser
3536

3637
from ...utils import _is_submodule
3738
from .context import Context
@@ -43,10 +44,11 @@
4344
if TYPE_CHECKING:
4445
from collections.abc import Callable, Coroutine, Iterable, Mapping
4546

47+
from twitchio.authentication.payloads import ClientCredentialsPayload, ValidateTokenPayload
4648
from twitchio.eventsub.subscriptions import SubscriptionPayload
4749
from twitchio.models.eventsub_ import ChannelPointsRedemptionAdd, ChannelPointsRedemptionUpdate, ChatMessage
4850
from twitchio.types_.eventsub import SubscriptionResponse
49-
from twitchio.user import PartialUser
51+
from twitchio.user import User
5052

5153
from .components import Component
5254
from .types_ import BotOptions
@@ -176,6 +178,7 @@ def __init__(
176178
self._components: dict[str, Component] = {}
177179
self._base_converter: _BaseConverter = _BaseConverter(self)
178180
self.__modules: dict[str, types.ModuleType] = {}
181+
self._owner: User | None = None
179182

180183
@property
181184
def bot_id(self) -> str:
@@ -204,6 +207,64 @@ def owner_id(self) -> str | None:
204207
"""
205208
return self._owner_id
206209

210+
@property
211+
def owner(self) -> User | None:
212+
"""Property which returns the :class:`~twitchio.User` associated with with the User who owns this bot.
213+
214+
Could be ``None`` if no ``owner_id`` was passed to the Bot constructor or the request failed.
215+
Passing a ``owner_id`` is highly recommended.
216+
217+
.. important::
218+
219+
If ``owner_id`` has not been passed to the constructor of this :class:`.Bot` this will return ``None``.
220+
"""
221+
return self._owner
222+
223+
async def login(self, *, token: str | None = None, load_tokens: bool = True, save_tokens: bool = True) -> None:
224+
if self._login_called:
225+
return
226+
227+
self._login_called = True
228+
self._save_tokens = save_tokens
229+
230+
if not self._http.client_id:
231+
raise RuntimeError('Expected a valid "client_id", instead received: %s', self._http.client_id)
232+
233+
if not token and not self._http.client_secret:
234+
raise RuntimeError(f'Expected a valid "client_secret", instead received: {self._http.client_secret}')
235+
236+
if not token:
237+
payload: ClientCredentialsPayload = await self._http.client_credentials_token()
238+
validated: ValidateTokenPayload = await self._http.validate_token(payload.access_token)
239+
token = payload.access_token
240+
241+
logger.info("Generated App Token for Client-ID: %s", validated.client_id)
242+
243+
self._http._app_token = token
244+
245+
if load_tokens:
246+
async with self._http._token_lock:
247+
await self.load_tokens()
248+
249+
if self._bot_id:
250+
logger.debug("Fetching Clients self user for %r", self.__class__.__name__)
251+
partial = PartialUser(id=self._bot_id, http=self._http)
252+
self._user = await partial.user() if self._fetch_self else partial
253+
254+
if self._owner_id:
255+
logger.debug("Fetching owner User for %r", self.__class__.__name__)
256+
partial = PartialUser(id=self._owner_id, http=self._http)
257+
258+
try:
259+
user = await partial.user()
260+
except Exception:
261+
logger.warning("Failed to retrieve the Owner User during startup. Owner will be None.")
262+
else:
263+
self._owner = user
264+
265+
await self.setup_hook()
266+
self._setup_called = True
267+
207268
async def close(self, **options: Any) -> None:
208269
for module in tuple(self.__modules):
209270
try:

0 commit comments

Comments
 (0)