diff --git a/interactions/api/models/channel.py b/interactions/api/models/channel.py index 400560f3a..9ababdc15 100644 --- a/interactions/api/models/channel.py +++ b/interactions/api/models/channel.py @@ -650,7 +650,7 @@ async def modify( auto_archive_duration: Optional[int] = MISSING, locked: Optional[bool] = MISSING, reason: Optional[str] = None, - ) -> "Channel": + ) -> "Channel": # sourcery skip: low-code-quality """ Edits the channel. @@ -1062,11 +1062,12 @@ async def get_message( async def purge( self, amount: int, - check: Callable[[Any], bool] = MISSING, + check: Optional[Callable[[Any], Union[bool, Awaitable[bool]]]] = MISSING, before: Optional[int] = MISSING, reason: Optional[str] = None, bulk: Optional[bool] = True, - ) -> List["Message"]: # noqa # sourcery skip: low-code-quality + force_bulk: Optional[bool] = False, + ) -> List["Message"]: """ Purges a given amount of messages from a channel. You can specify a check function to exclude specific messages. @@ -1076,13 +1077,25 @@ async def purge( def check_pinned(message): return not message.pinned # This returns `True` only if the message is the message is not pinned - await channel.purge(100, check=check_pinned) # This will delete the newest 100 messages that are not pinned in that channel + await channel.purge(100, check=check_pinned) + # This will delete the newest 100 messages that are not pinned in that channel :param int amount: The amount of messages to delete - :param Callable[[Message], bool] check: The function used to check if a message should be deleted. The message is only deleted if the check returns `True` + :param Optional[Callable[[Any], Union[bool, Awaitable[bool]]]] check: + The function used to check if a message should be deleted. + The message is only deleted if the check returns `True` :param Optional[int] before: An id of a message to purge only messages before that message - :param Optional[bool] bulk: Whether to bulk delete the messages (you cannot delete messages older than 14 days, default) or to delete every message seperately - :param Optional[str] reason: The reason of the deletes + :param Optional[bool] bulk: + Whether to use the bulk delete endpoint for deleting messages. This only works for 14 days + + .. versionchanged:: 4.4.0 + Purge now automatically continues deleting messages even after the 14 days limit was hit. Check + ``force_bulk`` for more information. If the 14 days span is exceeded the bot will encounter rate-limits + more frequently. + :param Optional[st] reason: The reason of the deletes + :param Optional[bool] force_bulk: + .. versionadded:: 4.4.0 + Whether to stop deleting messages when the 14 days bulk limit was hit, default ``False`` :return: A list of the deleted messages :rtype: List[Message] """ @@ -1092,7 +1105,46 @@ def check_pinned(message): _before = None if before is MISSING else before _all = [] - if bulk: + + async def normal_delete(): + nonlocal _before, _all, amount, check, reason + while amount > 0: + messages = [ + Message(**res) + for res in await self._client.get_channel_messages( + channel_id=int(self.id), + limit=min(amount, 100), + before=_before, + ) + ] + + amount -= min(amount, 100) + messages2 = messages.copy() + for message in messages2: + if message.flags == (1 << 7): + messages.remove(message) + amount += 1 + _before = int(message.id) + elif check is not MISSING: + _check = check(message) + if isawaitable(_check): + _check = await _check + if not _check: + messages.remove(message) + amount += 1 + _before = int(message.id) + _all += messages + + for message in _all: + await self._client.delete_message( + channel_id=int(self.id), + message_id=int(message.id), + reason=reason, + ) + + async def bulk_delete(): + nonlocal _before, _all, amount, check, reason + _allowed_time = datetime.now(tz=timezone.utc) - timedelta(days=14) _stop = False while amount > 100: @@ -1118,6 +1170,8 @@ def check_pinned(message): _before = int(message.id) elif check is not MISSING: _check = check(message) + if isawaitable(_check): + _check = await _check if not _check: messages.remove(message) amount += 1 @@ -1167,6 +1221,8 @@ def check_pinned(message): _before = int(message.id) elif check is not MISSING: _check = check(message) + if isawaitable(_check): + _check = await _check if not _check: messages.remove(message) amount += 1 @@ -1208,6 +1264,8 @@ def check_pinned(message): _before = int(message.id) elif check is not MISSING: _check = check(message) + if isawaitable(_check): + _check = await _check if not _check: messages.remove(message) amount += 1 @@ -1221,38 +1279,13 @@ def check_pinned(message): reason=reason, ) - else: - while amount > 0: - messages = [ - Message(**res) - for res in await self._client.get_channel_messages( - channel_id=int(self.id), - limit=min(amount, 100), - before=_before, - ) - ] - - amount -= min(amount, 100) - messages2 = messages.copy() - for message in messages2: - if message.flags == (1 << 7): - messages.remove(message) - amount += 1 - _before = int(message.id) - elif check is not MISSING: - _check = check(message) - if not _check: - messages.remove(message) - amount += 1 - _before = int(message.id) - _all += messages + if bulk: + await bulk_delete() + if not force_bulk: + await normal_delete() + return _all - for message in _all: - await self._client.delete_message( - channel_id=int(self.id), - message_id=int(message.id), - reason=reason, - ) + await normal_delete() return _all @@ -1601,7 +1634,7 @@ async def create_forum_post( files: Optional[List[File]] = MISSING, rate_limit_per_user: Optional[int] = MISSING, reason: Optional[str] = None, - ) -> "Channel": + ) -> "Channel": # sourcery skip: low-code-quality """ Creates a new post inside a forum channel