Browse Source

Merge branch 'master' into feature/guild_onboarding

pull/9260/head
Josh 2 years ago
parent
commit
a8501385ea
  1. 2
      discord/app_commands/models.py
  2. 24
      discord/audit_logs.py
  3. 4
      discord/channel.py
  4. 21
      discord/ext/commands/core.py
  5. 11
      discord/flags.py
  6. 11
      discord/guild.py
  7. 2
      discord/message.py
  8. 1
      discord/state.py
  9. 4
      discord/threads.py
  10. 2
      discord/utils.py
  11. 38
      docs/api.rst
  12. 7
      docs/discord.rst
  13. BIN
      docs/images/discord_create_bot_user.png

2
discord/app_commands/models.py

@ -673,7 +673,7 @@ class AppCommandThread(Hashable):
archiver_id: Optional[:class:`int`] archiver_id: Optional[:class:`int`]
The user's ID that archived this thread. The user's ID that archived this thread.
auto_archive_duration: :class:`int` auto_archive_duration: :class:`int`
The duration in minutes until the thread is automatically archived due to inactivity. The duration in minutes until the thread is automatically hidden from the channel list.
Usually a value of 60, 1440, 4320 and 10080. Usually a value of 60, 1440, 4320 and 10080.
archive_timestamp: :class:`datetime.datetime` archive_timestamp: :class:`datetime.datetime`
An aware timestamp of when the thread's archived status was last updated in UTC. An aware timestamp of when the thread's archived status was last updated in UTC.

24
discord/audit_logs.py

@ -76,6 +76,7 @@ if TYPE_CHECKING:
from .types.onboarding import Prompt as PromptPayload, PromptOption as PromptOptionPayload from .types.onboarding import Prompt as PromptPayload, PromptOption as PromptOptionPayload
from .user import User from .user import User
from .app_commands import AppCommand from .app_commands import AppCommand
from .webhook import Webhook
TargetType = Union[ TargetType = Union[
Guild, Guild,
@ -91,6 +92,9 @@ if TYPE_CHECKING:
Object, Object,
PartialIntegration, PartialIntegration,
AutoModRule, AutoModRule,
ScheduledEvent,
Webhook,
AppCommand,
None, None,
] ]
@ -597,6 +601,7 @@ class AuditLogEntry(Hashable):
integrations: Mapping[int, PartialIntegration], integrations: Mapping[int, PartialIntegration],
app_commands: Mapping[int, AppCommand], app_commands: Mapping[int, AppCommand],
automod_rules: Mapping[int, AutoModRule], automod_rules: Mapping[int, AutoModRule],
webhooks: Mapping[int, Webhook],
data: AuditLogEntryPayload, data: AuditLogEntryPayload,
guild: Guild, guild: Guild,
): ):
@ -606,6 +611,7 @@ class AuditLogEntry(Hashable):
self._integrations: Mapping[int, PartialIntegration] = integrations self._integrations: Mapping[int, PartialIntegration] = integrations
self._app_commands: Mapping[int, AppCommand] = app_commands self._app_commands: Mapping[int, AppCommand] = app_commands
self._automod_rules: Mapping[int, AutoModRule] = automod_rules self._automod_rules: Mapping[int, AutoModRule] = automod_rules
self._webhooks: Mapping[int, Webhook] = webhooks
self._from_data(data) self._from_data(data)
def _from_data(self, data: AuditLogEntryPayload) -> None: def _from_data(self, data: AuditLogEntryPayload) -> None:
@ -744,12 +750,11 @@ class AuditLogEntry(Hashable):
if self.action.target_type is None: if self.action.target_type is None:
return None return None
if self._target_id is None:
return None
try: try:
converter = getattr(self, '_convert_target_' + self.action.target_type) converter = getattr(self, '_convert_target_' + self.action.target_type)
except AttributeError: except AttributeError:
if self._target_id is None:
return None
return Object(id=self._target_id) return Object(id=self._target_id)
else: else:
return converter(self._target_id) return converter(self._target_id)
@ -782,7 +787,12 @@ class AuditLogEntry(Hashable):
def _convert_target_channel(self, target_id: int) -> Union[abc.GuildChannel, Object]: def _convert_target_channel(self, target_id: int) -> Union[abc.GuildChannel, Object]:
return self.guild.get_channel(target_id) or Object(id=target_id) return self.guild.get_channel(target_id) or Object(id=target_id)
def _convert_target_user(self, target_id: int) -> Union[Member, User, Object]: def _convert_target_user(self, target_id: Optional[int]) -> Optional[Union[Member, User, Object]]:
# For some reason the member_disconnect and member_move action types
# do not have a non-null target_id so safeguard against that
if target_id is None:
return None
return self._get_member(target_id) or Object(id=target_id, type=Member) return self._get_member(target_id) or Object(id=target_id, type=Member)
def _convert_target_role(self, target_id: int) -> Union[Role, Object]: def _convert_target_role(self, target_id: int) -> Union[Role, Object]:
@ -862,3 +872,9 @@ class AuditLogEntry(Hashable):
def _convert_target_auto_moderation(self, target_id: int) -> Union[AutoModRule, Object]: def _convert_target_auto_moderation(self, target_id: int) -> Union[AutoModRule, Object]:
return self._automod_rules.get(target_id) or Object(target_id, type=AutoModRule) return self._automod_rules.get(target_id) or Object(target_id, type=AutoModRule)
def _convert_target_webhook(self, target_id: int) -> Union[Webhook, Object]:
# circular import
from .webhook import Webhook
return self._webhooks.get(target_id) or Object(target_id, type=Webhook)

4
discord/channel.py

@ -737,7 +737,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
If ``None`` is passed then a private thread is created. If ``None`` is passed then a private thread is created.
Defaults to ``None``. Defaults to ``None``.
auto_archive_duration: :class:`int` auto_archive_duration: :class:`int`
The duration in minutes before a thread is automatically archived for inactivity. The duration in minutes before a thread is automatically hidden from the channel list.
If not provided, the channel's default auto archive duration is used. If not provided, the channel's default auto archive duration is used.
Must be one of ``60``, ``1440``, ``4320``, or ``10080``, if provided. Must be one of ``60``, ``1440``, ``4320``, or ``10080``, if provided.
@ -2607,7 +2607,7 @@ class ForumChannel(discord.abc.GuildChannel, Hashable):
name: :class:`str` name: :class:`str`
The name of the thread. The name of the thread.
auto_archive_duration: :class:`int` auto_archive_duration: :class:`int`
The duration in minutes before a thread is automatically archived for inactivity. The duration in minutes before a thread is automatically hidden from the channel list.
If not provided, the channel's default auto archive duration is used. If not provided, the channel's default auto archive duration is used.
Must be one of ``60``, ``1440``, ``4320``, or ``10080``, if provided. Must be one of ``60``, ``1440``, ``4320``, or ``10080``, if provided.

21
discord/ext/commands/core.py

@ -2036,7 +2036,7 @@ def has_role(item: Union[int, str], /) -> Check[Any]:
# ctx.guild is None doesn't narrow ctx.author to Member # ctx.guild is None doesn't narrow ctx.author to Member
if isinstance(item, int): if isinstance(item, int):
role = discord.utils.get(ctx.author.roles, id=item) # type: ignore role = ctx.author.get_role(item) # type: ignore
else: else:
role = discord.utils.get(ctx.author.roles, name=item) # type: ignore role = discord.utils.get(ctx.author.roles, name=item) # type: ignore
if role is None: if role is None:
@ -2083,8 +2083,12 @@ def has_any_role(*items: Union[int, str]) -> Callable[[T], T]:
raise NoPrivateMessage() raise NoPrivateMessage()
# ctx.guild is None doesn't narrow ctx.author to Member # ctx.guild is None doesn't narrow ctx.author to Member
getter = functools.partial(discord.utils.get, ctx.author.roles) if any(
if any(getter(id=item) is not None if isinstance(item, int) else getter(name=item) is not None for item in items): ctx.author.get_role(item) is not None
if isinstance(item, int)
else discord.utils.get(ctx.author.roles, name=item) is not None
for item in items
):
return True return True
raise MissingAnyRole(list(items)) raise MissingAnyRole(list(items))
@ -2113,11 +2117,10 @@ def bot_has_role(item: int, /) -> Callable[[T], T]:
if ctx.guild is None: if ctx.guild is None:
raise NoPrivateMessage() raise NoPrivateMessage()
me = ctx.me
if isinstance(item, int): if isinstance(item, int):
role = discord.utils.get(me.roles, id=item) role = ctx.me.get_role(item)
else: else:
role = discord.utils.get(me.roles, name=item) role = discord.utils.get(ctx.me.roles, name=item)
if role is None: if role is None:
raise BotMissingRole(item) raise BotMissingRole(item)
return True return True
@ -2144,8 +2147,10 @@ def bot_has_any_role(*items: int) -> Callable[[T], T]:
raise NoPrivateMessage() raise NoPrivateMessage()
me = ctx.me me = ctx.me
getter = functools.partial(discord.utils.get, me.roles) if any(
if any(getter(id=item) is not None if isinstance(item, int) else getter(name=item) is not None for item in items): me.get_role(item) is not None if isinstance(item, int) else discord.utils.get(me.roles, name=item) is not None
for item in items
):
return True return True
raise BotMissingAnyRole(list(items)) raise BotMissingAnyRole(list(items))

11
discord/flags.py

@ -25,6 +25,7 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations from __future__ import annotations
from functools import reduce from functools import reduce
from operator import or_
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, Iterator, List, Optional, Tuple, Type, TypeVar, overload from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, Iterator, List, Optional, Tuple, Type, TypeVar, overload
from .enums import UserFlags from .enums import UserFlags
@ -1566,7 +1567,15 @@ class ArrayFlags(BaseFlags):
@classmethod @classmethod
def _from_value(cls: Type[Self], value: List[int]) -> Self: def _from_value(cls: Type[Self], value: List[int]) -> Self:
self = cls.__new__(cls) self = cls.__new__(cls)
self.value = reduce(lambda a, b: a | (1 << b - 1), value, 0) # This is a micro-optimization given the frequency this object can be created.
# (1).__lshift__ is used in place of lambda x: 1 << x
# prebinding to a method of a constant rather than define a lambda.
# Pairing this with map, is essentially equivalent to (1 << x for x in value)
# reduction using operator.or_ instead of defining a lambda each call
# Discord sends these starting with a value of 1
# Rather than subtract 1 from each element prior to left shift,
# we shift right by 1 once at the end.
self.value = reduce(or_, map((1).__lshift__, value), 0) >> 1
return self return self
def to_array(self) -> List[int]: def to_array(self) -> List[int]:

11
discord/guild.py

@ -319,9 +319,9 @@ class Guild(Hashable):
) )
_PREMIUM_GUILD_LIMITS: ClassVar[Dict[Optional[int], _GuildLimit]] = { _PREMIUM_GUILD_LIMITS: ClassVar[Dict[Optional[int], _GuildLimit]] = {
None: _GuildLimit(emoji=50, stickers=5, bitrate=96e3, filesize=8388608), None: _GuildLimit(emoji=50, stickers=5, bitrate=96e3, filesize=26214400),
0: _GuildLimit(emoji=50, stickers=5, bitrate=96e3, filesize=8388608), 0: _GuildLimit(emoji=50, stickers=5, bitrate=96e3, filesize=26214400),
1: _GuildLimit(emoji=100, stickers=15, bitrate=128e3, filesize=8388608), 1: _GuildLimit(emoji=100, stickers=15, bitrate=128e3, filesize=26214400),
2: _GuildLimit(emoji=150, stickers=30, bitrate=256e3, filesize=52428800), 2: _GuildLimit(emoji=150, stickers=30, bitrate=256e3, filesize=52428800),
3: _GuildLimit(emoji=250, stickers=60, bitrate=384e3, filesize=104857600), 3: _GuildLimit(emoji=250, stickers=60, bitrate=384e3, filesize=104857600),
} }
@ -3861,6 +3861,7 @@ class Guild(Hashable):
# avoid circular import # avoid circular import
from .app_commands import AppCommand from .app_commands import AppCommand
from .webhook import Webhook
while True: while True:
retrieve = 100 if limit is None else min(limit, 100) retrieve = 100 if limit is None else min(limit, 100)
@ -3887,6 +3888,9 @@ class Guild(Hashable):
) )
automod_rule_map = {rule.id: rule for rule in automod_rules} automod_rule_map = {rule.id: rule for rule in automod_rules}
webhooks = (Webhook.from_state(data=raw_webhook, state=self._state) for raw_webhook in data.get('webhooks', []))
webhook_map = {webhook.id: webhook for webhook in webhooks}
count = 0 count = 0
for count, raw_entry in enumerate(raw_entries, 1): for count, raw_entry in enumerate(raw_entries, 1):
@ -3900,6 +3904,7 @@ class Guild(Hashable):
integrations=integration_map, integrations=integration_map,
app_commands=app_command_map, app_commands=app_command_map,
automod_rules=automod_rule_map, automod_rules=automod_rule_map,
webhooks=webhook_map,
guild=self, guild=self,
) )

2
discord/message.py

@ -1215,7 +1215,7 @@ class PartialMessage(Hashable):
name: :class:`str` name: :class:`str`
The name of the thread. The name of the thread.
auto_archive_duration: :class:`int` auto_archive_duration: :class:`int`
The duration in minutes before a thread is automatically archived for inactivity. The duration in minutes before a thread is automatically hidden from the channel list.
If not provided, the channel's default auto archive duration is used. If not provided, the channel's default auto archive duration is used.
Must be one of ``60``, ``1440``, ``4320``, or ``10080``, if provided. Must be one of ``60``, ``1440``, ``4320``, or ``10080``, if provided.

1
discord/state.py

@ -1108,6 +1108,7 @@ class ConnectionState(Generic[ClientT]):
integrations={}, integrations={},
app_commands={}, app_commands={},
automod_rules={}, automod_rules={},
webhooks={},
data=data, data=data,
guild=guild, guild=guild,
) )

4
discord/threads.py

@ -122,7 +122,7 @@ class Thread(Messageable, Hashable):
archiver_id: Optional[:class:`int`] archiver_id: Optional[:class:`int`]
The user's ID that archived this thread. The user's ID that archived this thread.
auto_archive_duration: :class:`int` auto_archive_duration: :class:`int`
The duration in minutes until the thread is automatically archived due to inactivity. The duration in minutes until the thread is automatically hidden from the channel list.
Usually a value of 60, 1440, 4320 and 10080. Usually a value of 60, 1440, 4320 and 10080.
archive_timestamp: :class:`datetime.datetime` archive_timestamp: :class:`datetime.datetime`
An aware timestamp of when the thread's archived status was last updated in UTC. An aware timestamp of when the thread's archived status was last updated in UTC.
@ -608,7 +608,7 @@ class Thread(Messageable, Hashable):
Whether non-moderators can add other non-moderators to this thread. Whether non-moderators can add other non-moderators to this thread.
Only available for private threads. Only available for private threads.
auto_archive_duration: :class:`int` auto_archive_duration: :class:`int`
The new duration in minutes before a thread is automatically archived for inactivity. The new duration in minutes before a thread is automatically hidden from the channel list.
Must be one of ``60``, ``1440``, ``4320``, or ``10080``. Must be one of ``60``, ``1440``, ``4320``, or ``10080``.
slowmode_delay: :class:`int` slowmode_delay: :class:`int`
Specifies the slowmode rate limit for user in this thread, in seconds. Specifies the slowmode rate limit for user in this thread, in seconds.

2
discord/utils.py

@ -900,7 +900,7 @@ _MARKDOWN_ESCAPE_REGEX = re.compile(fr'(?P<markdown>{_MARKDOWN_ESCAPE_SUBREGEX}|
_URL_REGEX = r'(?P<url><[^: >]+:\/[^ >]+>|(?:https?|steam):\/\/[^\s<]+[^<.,:;\"\'\]\s])' _URL_REGEX = r'(?P<url><[^: >]+:\/[^ >]+>|(?:https?|steam):\/\/[^\s<]+[^<.,:;\"\'\]\s])'
_MARKDOWN_STOCK_REGEX = fr'(?P<markdown>[_\\~|\*`]|{_MARKDOWN_ESCAPE_COMMON})' _MARKDOWN_STOCK_REGEX = fr'(?P<markdown>[_\\~|\*`#-]|{_MARKDOWN_ESCAPE_COMMON})'
def remove_markdown(text: str, *, ignore_links: bool = True) -> str: def remove_markdown(text: str, *, ignore_links: bool = True) -> str:

38
docs/api.rst

@ -3477,6 +3477,12 @@ AuditLogDiff
:type: :class:`str` :type: :class:`str`
.. attribute:: guild
The guild of something.
:type: :class:`Guild`
.. attribute:: icon .. attribute:: icon
A guild's or role's icon. See also :attr:`Guild.icon` or :attr:`Role.icon`. A guild's or role's icon. See also :attr:`Guild.icon` or :attr:`Role.icon`.
@ -4051,6 +4057,38 @@ AuditLogDiff
:type: :class:`ChannelFlags` :type: :class:`ChannelFlags`
.. attribute:: default_thread_slowmode_delay
The default slowmode delay for threads created in this text channel or forum.
See also :attr:`TextChannel.default_thread_slowmode_delay` and :attr:`ForumChannel.default_thread_slowmode_delay`
:type: :class:`int`
.. attribute:: applied_tags
The applied tags of a forum post.
See also :attr:`Thread.applied_tags`
:type: List[Union[:class:`ForumTag`, :class:`Object`]]
.. attribute:: available_tags
The available tags of a forum.
See also :attr:`ForumChannel.available_tags`
:type: Sequence[:class:`ForumTag`]
.. attribute:: default_reaction_emoji
The default_reaction_emoji for forum posts.
See also :attr:`ForumChannel.default_reaction_emoji`
:type: :class:`default_reaction_emoji`
.. attribute:: options .. attribute:: options
The onboarding prompt options associated with this onboarding prompt. The onboarding prompt options associated with this onboarding prompt.

7
docs/discord.rst

@ -21,12 +21,7 @@ Creating a Bot account is a pretty straightforward process.
.. image:: /images/discord_create_app_form.png .. image:: /images/discord_create_app_form.png
:alt: The new application form filled in. :alt: The new application form filled in.
5. Create a Bot User by navigating to the "Bot" tab and clicking "Add Bot". 5. Navigate to the "Bot" tab to configure it.
- Click "Yes, do it!" to continue.
.. image:: /images/discord_create_bot_user.png
:alt: The Add Bot button.
6. Make sure that **Public Bot** is ticked if you want others to invite your bot. 6. Make sure that **Public Bot** is ticked if you want others to invite your bot.
- You should also make sure that **Require OAuth2 Code Grant** is unchecked unless you - You should also make sure that **Require OAuth2 Code Grant** is unchecked unless you

BIN
docs/images/discord_create_bot_user.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Loading…
Cancel
Save