Skip to content

Commit

Permalink
Merge branch 'master' into role-connections
Browse files Browse the repository at this point in the history
  • Loading branch information
Lulalaby authored Jan 5, 2023
2 parents 2fcc9a0 + 0c1e611 commit aca3f76
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 32 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ These changes are available on the `master` branch, but have not yet been releas

## Added

- Added new AutoMod trigger metadata properties `regex_patterns`, `allow_list`, and
`mention_total_limit`; and added the `mention_spam` trigger type.
([#1809](https://github.com/Pycord-Development/pycord/pull/1809))
- Added missing `image` parameter to `Guild.create_scheduled_event()` method.
([#1831](https://github.com/Pycord-Development/pycord/pull/1831))
- New `ApplicationRoleConnectionMetadata` class for application role connection
metadata, along with the `fetch_role_connection_metadata_records` and
`update_role_connection_metadata_records` methods in `Client`.
Expand Down
85 changes: 76 additions & 9 deletions discord/automod.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@
from .mixins import Hashable
from .object import Object

__all__ = ("AutoModRule",)
__all__ = (
"AutoModRule",
"AutoModAction",
"AutoModActionMetadata",
"AutoModTriggerMetadata",
)

if TYPE_CHECKING:
from .abc import Snowflake
Expand Down Expand Up @@ -167,45 +172,95 @@ def __repr__(self) -> str:


class AutoModTriggerMetadata:
"""Represents a rule's trigger metadata.
Depending on the trigger type, different attributes will be used.
r"""Represents a rule's trigger metadata, defining additional data used to determine when a rule triggers.
Depending on the trigger type, different metadata attributes will be used:
+-----------------------------+--------------------------------------------------------------------------------+
| Attribute | Trigger Types |
+=============================+================================================================================+
| :attr:`keyword_filter` | :attr:`AutoModTriggerType.keyword` |
+-----------------------------+--------------------------------------------------------------------------------+
| :attr:`regex_patterns` | :attr:`AutoModTriggerType.keyword` |
+-----------------------------+--------------------------------------------------------------------------------+
| :attr:`presets` | :attr:`AutoModTriggerType.keyword_preset` |
+-----------------------------+--------------------------------------------------------------------------------+
| :attr:`allow_list` | :attr:`AutoModTriggerType.keyword`\, :attr:`AutoModTriggerType.keyword_preset` |
+-----------------------------+--------------------------------------------------------------------------------+
| :attr:`mention_total_limit` | :attr:`AutoModTriggerType.mention_spam` |
+-----------------------------+--------------------------------------------------------------------------------+
Each attribute has limits that may change based on the trigger type.
See `here <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata-field-limits>`_
for information on attribute limits.
.. versionadded:: 2.0
Attributes
----------
keyword_filter: List[:class:`str`]
A list of substrings to filter. Only for triggers of type :attr:`AutoModTriggerType.keyword`.
A list of substrings to filter.
regex_patterns: List[:class:`str`]
A list of regex patterns to filter using Rust-flavored regex, which is not
fully compatible with regex syntax supported by the builtin `re` module.
.. versionadded:: 2.4
presets: List[:class:`AutoModKeywordPresetType`]
A list of keyword presets to filter. Only for triggers of type :attr:`AutoModTriggerType.keyword_preset`.
"""
A list of preset keyword sets to filter.
# maybe add a table of action types and attributes?
# wording for presets could change
allow_list: List[:class:`str`]
A list of substrings to allow, overriding keyword and regex matches.
.. versionadded:: 2.4
mention_total_limit: :class:`int`
The total number of unique role and user mentions allowed.
.. versionadded:: 2.4
"""

__slots__ = (
"keyword_filter",
"regex_patterns",
"presets",
"allow_list",
"mention_total_limit",
)

def __init__(
self,
keyword_filter: list[str] = MISSING,
regex_patterns: list[str] = MISSING,
presets: list[AutoModKeywordPresetType] = MISSING,
allow_list: list[str] = MISSING,
mention_total_limit: int = MISSING,
):
self.keyword_filter = keyword_filter
self.regex_patterns = regex_patterns
self.presets = presets
self.allow_list = allow_list
self.mention_total_limit = mention_total_limit

def to_dict(self) -> dict:
data = {}

if self.keyword_filter is not MISSING:
data["keyword_filter"] = self.keyword_filter

if self.regex_patterns is not MISSING:
data["regex_patterns"] = self.regex_patterns

if self.presets is not MISSING:
data["presets"] = [wordset.value for wordset in self.presets]

if self.allow_list is not MISSING:
data["allow_list"] = self.allow_list

if self.mention_total_limit is not MISSING:
data["mention_total_limit"] = self.mention_total_limit

return data

@classmethod
Expand All @@ -215,17 +270,29 @@ def from_dict(cls, data: AutoModTriggerMetadataPayload):
if (keyword_filter := data.get("keyword_filter")) is not None:
kwargs["keyword_filter"] = keyword_filter

if (regex_patterns := data.get("regex_patterns")) is not None:
kwargs["regex_patterns"] = regex_patterns

if (presets := data.get("presets")) is not None:
kwargs["presets"] = [
try_enum(AutoModKeywordPresetType, wordset) for wordset in presets
]

if (allow_list := data.get("allow_list")) is not None:
kwargs["allow_list"] = allow_list

if (mention_total_limit := data.get("mention_total_limit")) is not None:
kwargs["mention_total_limit"] = mention_total_limit

return cls(**kwargs)

def __repr__(self) -> str:
repr_attrs = (
"keyword_filter",
"regex_patterns",
"presets",
"allow_list",
"mention_total_limit",
)
inner = []

Expand Down
1 change: 1 addition & 0 deletions discord/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,7 @@ class AutoModTriggerType(Enum):
harmful_link = 2
spam = 3
keyword_preset = 4
mention_spam = 5


class AutoModEventType(Enum):
Expand Down
23 changes: 13 additions & 10 deletions discord/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -2156,13 +2156,14 @@ async def fetch_channel(self, channel_id: int, /) -> GuildChannel | Thread:
def bans(
self,
limit: int | None = None,
before: SnowflakeTime | None = None,
after: SnowflakeTime | None = None,
before: Snowflake | None = None,
after: Snowflake | None = None,
) -> BanIterator:
"""|coro|
Retrieves an :class:`.AsyncIterator` that enables receiving the guild's bans. In order to use this, you must
have the :attr:`~Permissions.ban_members` permission.
Users will always be returned in ascending order sorted by user ID. If both the ``before`` and ``after`` parameters are provided, only before is respected.
.. versionchanged:: 2.0
The ``limit``, ``before``. and ``after`` parameters were added. Now returns a :class:`.BanIterator` instead
Expand All @@ -2174,14 +2175,10 @@ def bans(
----------
limit: Optional[:class:`int`]
The number of bans to retrieve. Defaults to 1000.
before: Optional[Union[:class:`.abc.Snowflake`, :class:`datetime.datetime`]]
Retrieve bans before this date or object.
If a datetime is provided, it is recommended to use a UTC aware datetime.
If the datetime is naive, it is assumed to be local time.
after: Optional[Union[:class:`.abc.Snowflake`, :class:`datetime.datetime`]]
Retrieve bans after this date or object.
If a datetime is provided, it is recommended to use a UTC aware datetime.
If the datetime is naive, it is assumed to be local time.
before: Optional[:class:`.abc.Snowflake`]
Retrieve bans before the given user.
after: Optional[:class:`.abc.Snowflake`]
Retrieve bans after the given user.
Yields
------
Expand Down Expand Up @@ -3650,6 +3647,7 @@ async def create_scheduled_event(
location: str | int | VoiceChannel | StageChannel | ScheduledEventLocation,
privacy_level: ScheduledEventPrivacyLevel = ScheduledEventPrivacyLevel.guild_only,
reason: str | None = None,
image: bytes = MISSING,
) -> ScheduledEvent | None:
"""|coro|
Creates a scheduled event.
Expand All @@ -3672,6 +3670,8 @@ async def create_scheduled_event(
so there is no need to change this parameter.
reason: Optional[:class:`str`]
The reason to show in the audit log.
image: Optional[:class:`bytes`]
The cover image of the scheduled event
Returns
-------
Expand Down Expand Up @@ -3709,6 +3709,9 @@ async def create_scheduled_event(
if end_time is not MISSING:
payload["scheduled_end_time"] = end_time.isoformat()

if image is not MISSING:
payload["image"] = utils._bytes_to_base64_data(image)

data = await self._state.http.create_scheduled_event(
guild_id=self.id, reason=reason, **payload
)
Expand Down
1 change: 1 addition & 0 deletions discord/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -2232,6 +2232,7 @@ def create_scheduled_event(
"description",
"entity_type",
"entity_metadata",
"image",
)
payload = {k: v for k, v in payload.items() if k in valid_keys}

Expand Down
5 changes: 0 additions & 5 deletions discord/iterators.py
Original file line number Diff line number Diff line change
Expand Up @@ -689,11 +689,6 @@ def create_member(self, data):

class BanIterator(_AsyncIterator["BanEntry"]):
def __init__(self, guild, limit=None, before=None, after=None):
if isinstance(after, datetime.datetime):
after = Object(id=time_snowflake(after, high=True))

if isinstance(before, datetime.datetime):
before = Object(id=time_snowflake(before, high=True))

self.guild = guild
self.limit = limit
Expand Down
6 changes: 3 additions & 3 deletions discord/opus.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def _err_ne(result: T, func: Callable, args: list) -> T:
# The fourth is the error handler.
exported_functions: list[tuple[Any, ...]] = [
# Generic
("opus_get_version_string", None, ctypes.c_char_p, None),
("opus_get_version_string", [], ctypes.c_char_p, None),
("opus_strerror", [ctypes.c_int], ctypes.c_char_p, None),
# Encoder functions
("opus_encoder_get_size", [ctypes.c_int], ctypes.c_int, None),
Expand All @@ -169,7 +169,7 @@ def _err_ne(result: T, func: Callable, args: list) -> T:
ctypes.c_int32,
_err_lt,
),
("opus_encoder_ctl", None, ctypes.c_int32, _err_lt),
("opus_encoder_ctl", [EncoderStructPtr, ctypes.c_int], ctypes.c_int32, _err_lt),
("opus_encoder_destroy", [EncoderStructPtr], None, None),
# Decoder functions
("opus_decoder_get_size", [ctypes.c_int], ctypes.c_int, None),
Expand Down Expand Up @@ -205,7 +205,7 @@ def _err_ne(result: T, func: Callable, args: list) -> T:
ctypes.c_int,
_err_lt,
),
("opus_decoder_ctl", None, ctypes.c_int32, _err_lt),
("opus_decoder_ctl", [DecoderStructPtr, ctypes.c_int], ctypes.c_int32, _err_lt),
("opus_decoder_destroy", [DecoderStructPtr], None, None),
(
"opus_decoder_get_nb_samples",
Expand Down
10 changes: 9 additions & 1 deletion discord/raw_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import datetime
from typing import TYPE_CHECKING

from .automod import AutoModAction
from .automod import AutoModAction, AutoModTriggerType
from .enums import ChannelType, try_enum

if TYPE_CHECKING:
Expand Down Expand Up @@ -409,6 +409,10 @@ class AutoModActionExecutionEvent:
The action that was executed.
rule_id: :class:`int`
The ID of the rule that the action belongs to.
rule_trigger_type: :class:`AutoModTriggerType`
The category of trigger the rule belongs to.
.. versionadded:: 2.4
guild_id: :class:`int`
The ID of the guild that the action was executed in.
guild: Optional[:class:`Guild`]
Expand Down Expand Up @@ -443,6 +447,7 @@ class AutoModActionExecutionEvent:
__slots__ = (
"action",
"rule_id",
"rule_trigger_type",
"guild_id",
"guild",
"user_id",
Expand All @@ -461,6 +466,9 @@ class AutoModActionExecutionEvent:
def __init__(self, state: ConnectionState, data: AutoModActionExecution) -> None:
self.action: AutoModAction = AutoModAction.from_dict(data["action"])
self.rule_id: int = int(data["rule_id"])
self.rule_trigger_type: AutoModTriggerType = try_enum(
AutoModTriggerType, int(data["rule_trigger_type"])
)
self.guild_id: int = int(data["guild_id"])
self.guild: Guild | None = state._get_guild(self.guild_id)
self.user_id: int = int(data["user_id"])
Expand Down
5 changes: 4 additions & 1 deletion discord/types/automod.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from .._typed_dict import NotRequired, TypedDict
from .snowflake import Snowflake

AutoModTriggerType = Literal[1, 2, 3, 4]
AutoModTriggerType = Literal[1, 2, 3, 4, 5]

AutoModEventType = Literal[1]

Expand All @@ -38,7 +38,10 @@

class AutoModTriggerMetadata(TypedDict, total=False):
keyword_filter: list[str]
regex_patterns: list[str]
presets: list[AutoModKeywordPresetType]
allow_list: list[str]
mention_total_limit: int


class AutoModActionMetadata(TypedDict, total=False):
Expand Down
Loading

0 comments on commit aca3f76

Please sign in to comment.