Move purge and delete_messages from Messageable.
This is a breaking change. Move these two to TextChannel since the other things that implement Messageable cannot reliably do bulk delete actions in their respective channels.
This commit is contained in:
parent
f6fcb62c7b
commit
cbbc75cd8d
145
discord/abc.py
145
discord/abc.py
@ -27,14 +27,13 @@ DEALINGS IN THE SOFTWARE.
|
|||||||
import abc
|
import abc
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import time
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from .iterators import HistoryIterator
|
from .iterators import HistoryIterator
|
||||||
from .context_managers import Typing
|
from .context_managers import Typing
|
||||||
from .errors import ClientException, NoMoreItems, InvalidArgument
|
from .errors import InvalidArgument
|
||||||
from .permissions import PermissionOverwrite, Permissions
|
from .permissions import PermissionOverwrite, Permissions
|
||||||
from .role import Role
|
from .role import Role
|
||||||
from .invite import Invite
|
from .invite import Invite
|
||||||
@ -46,11 +45,6 @@ class _Undefined:
|
|||||||
|
|
||||||
_undefined = _Undefined()
|
_undefined = _Undefined()
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def _single_delete_strategy(messages):
|
|
||||||
for m in messages:
|
|
||||||
yield from m.delete()
|
|
||||||
|
|
||||||
class Snowflake(metaclass=abc.ABCMeta):
|
class Snowflake(metaclass=abc.ABCMeta):
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
@ -694,40 +688,6 @@ class Messageable(metaclass=abc.ABCMeta):
|
|||||||
data = yield from self._state.http.get_message(channel.id, id)
|
data = yield from self._state.http.get_message(channel.id, id)
|
||||||
return self._state.create_message(channel=channel, data=data)
|
return self._state.create_message(channel=channel, data=data)
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def delete_messages(self, messages):
|
|
||||||
"""|coro|
|
|
||||||
|
|
||||||
Deletes a list of messages. This is similar to :meth:`Message.delete`
|
|
||||||
except it bulk deletes multiple messages.
|
|
||||||
|
|
||||||
Usable only by bot accounts.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
-----------
|
|
||||||
messages : iterable of :class:`Message`
|
|
||||||
An iterable of messages denoting which ones to bulk delete.
|
|
||||||
|
|
||||||
Raises
|
|
||||||
------
|
|
||||||
ClientException
|
|
||||||
The number of messages to delete is less than 2 or more than 100.
|
|
||||||
Forbidden
|
|
||||||
You do not have proper permissions to delete the messages or
|
|
||||||
you're not using a bot account.
|
|
||||||
HTTPException
|
|
||||||
Deleting the messages failed.
|
|
||||||
"""
|
|
||||||
|
|
||||||
messages = list(messages)
|
|
||||||
if len(messages) > 100 or len(messages) < 2:
|
|
||||||
raise ClientException('Can only delete messages in the range of [2, 100]')
|
|
||||||
|
|
||||||
message_ids = [m.id for m in messages]
|
|
||||||
channel = yield from self._get_channel()
|
|
||||||
|
|
||||||
yield from self._state.http.delete_messages(channel.id, message_ids)
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def pins(self):
|
def pins(self):
|
||||||
"""|coro|
|
"""|coro|
|
||||||
@ -816,106 +776,3 @@ class Messageable(metaclass=abc.ABCMeta):
|
|||||||
counter += 1
|
counter += 1
|
||||||
"""
|
"""
|
||||||
return HistoryIterator(self, limit=limit, before=before, after=after, around=around, reverse=reverse)
|
return HistoryIterator(self, limit=limit, before=before, after=after, around=around, reverse=reverse)
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def purge(self, *, limit=100, check=None, before=None, after=None, around=None):
|
|
||||||
"""|coro|
|
|
||||||
|
|
||||||
Purges a list of messages that meet the criteria given by the predicate
|
|
||||||
``check``. If a ``check`` is not provided then all messages are deleted
|
|
||||||
without discrimination.
|
|
||||||
|
|
||||||
You must have :attr:`Permissions.manage_messages` permission to delete
|
|
||||||
messages even if they are your own (unless you are a user account).
|
|
||||||
The :attr:`Permissions.read_message_history` permission is also needed
|
|
||||||
to retrieve message history.
|
|
||||||
|
|
||||||
Internally, this employs a different number of strategies depending
|
|
||||||
on the conditions met such as if a bulk delete is possible or if
|
|
||||||
the account is a user bot or not.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
-----------
|
|
||||||
limit: int
|
|
||||||
The number of messages to search through. This is not the number
|
|
||||||
of messages that will be deleted, though it can be.
|
|
||||||
check: predicate
|
|
||||||
The function used to check if a message should be deleted.
|
|
||||||
It must take a :class:`Message` as its sole parameter.
|
|
||||||
before
|
|
||||||
Same as ``before`` in :meth:`history`.
|
|
||||||
after
|
|
||||||
Same as ``after`` in :meth:`history`.
|
|
||||||
around
|
|
||||||
Same as ``around`` in :meth:`history`.
|
|
||||||
|
|
||||||
Raises
|
|
||||||
-------
|
|
||||||
Forbidden
|
|
||||||
You do not have proper permissions to do the actions required.
|
|
||||||
HTTPException
|
|
||||||
Purging the messages failed.
|
|
||||||
|
|
||||||
Examples
|
|
||||||
---------
|
|
||||||
|
|
||||||
Deleting bot's messages ::
|
|
||||||
|
|
||||||
def is_me(m):
|
|
||||||
return m.author == client.user
|
|
||||||
|
|
||||||
deleted = await channel.purge(limit=100, check=is_me)
|
|
||||||
await channel.send_message('Deleted {} message(s)'.format(len(deleted)))
|
|
||||||
|
|
||||||
Returns
|
|
||||||
--------
|
|
||||||
list
|
|
||||||
The list of messages that were deleted.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if check is None:
|
|
||||||
check = lambda m: True
|
|
||||||
|
|
||||||
iterator = self.history(limit=limit, before=before, after=after, around=around)
|
|
||||||
ret = []
|
|
||||||
count = 0
|
|
||||||
|
|
||||||
minimum_time = int((time.time() - 14 * 24 * 60 * 60) * 1000.0 - 1420070400000) << 22
|
|
||||||
strategy = self.delete_messages if self._state.is_bot else _single_delete_strategy
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
msg = yield from iterator.get()
|
|
||||||
except NoMoreItems:
|
|
||||||
# no more messages to poll
|
|
||||||
if count >= 2:
|
|
||||||
# more than 2 messages -> bulk delete
|
|
||||||
to_delete = ret[-count:]
|
|
||||||
yield from strategy(to_delete)
|
|
||||||
elif count == 1:
|
|
||||||
# delete a single message
|
|
||||||
yield from ret[-1].delete()
|
|
||||||
|
|
||||||
return ret
|
|
||||||
else:
|
|
||||||
if count == 100:
|
|
||||||
# we've reached a full 'queue'
|
|
||||||
to_delete = ret[-100:]
|
|
||||||
yield from strategy(to_delete)
|
|
||||||
count = 0
|
|
||||||
yield from asyncio.sleep(1)
|
|
||||||
|
|
||||||
if check(msg):
|
|
||||||
if msg.id < minimum_time:
|
|
||||||
# older than 14 days old
|
|
||||||
if count == 1:
|
|
||||||
yield from ret[-1].delete()
|
|
||||||
elif count >= 2:
|
|
||||||
to_delete = ret[-count:]
|
|
||||||
yield from strategy(to_delete)
|
|
||||||
|
|
||||||
count = 0
|
|
||||||
strategy = _single_delete_strategy
|
|
||||||
|
|
||||||
count += 1
|
|
||||||
ret.append(msg)
|
|
||||||
|
@ -30,14 +30,21 @@ from .role import Role
|
|||||||
from .user import User
|
from .user import User
|
||||||
from .member import Member
|
from .member import Member
|
||||||
from . import utils
|
from . import utils
|
||||||
|
from .errors import ClientException, NoMoreItems
|
||||||
|
|
||||||
import discord.abc
|
import discord.abc
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import time
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
__all__ = ('TextChannel', 'VoiceChannel', 'DMChannel', 'GroupChannel', '_channel_factory')
|
__all__ = ('TextChannel', 'VoiceChannel', 'DMChannel', 'GroupChannel', '_channel_factory')
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def _single_delete_strategy(messages):
|
||||||
|
for m in messages:
|
||||||
|
yield from m.delete()
|
||||||
|
|
||||||
class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
|
class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
|
||||||
"""Represents a Discord guild text channel.
|
"""Represents a Discord guild text channel.
|
||||||
|
|
||||||
@ -141,6 +148,143 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
|
|||||||
data = yield from self._state.http.edit_channel(self.id, **options)
|
data = yield from self._state.http.edit_channel(self.id, **options)
|
||||||
self._update(self.guild, data)
|
self._update(self.guild, data)
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def delete_messages(self, messages):
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Deletes a list of messages. This is similar to :meth:`Message.delete`
|
||||||
|
except it bulk deletes multiple messages.
|
||||||
|
|
||||||
|
Usable only by bot accounts.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
messages : iterable of :class:`Message`
|
||||||
|
An iterable of messages denoting which ones to bulk delete.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
ClientException
|
||||||
|
The number of messages to delete is less than 2 or more than 100.
|
||||||
|
Forbidden
|
||||||
|
You do not have proper permissions to delete the messages or
|
||||||
|
you're not using a bot account.
|
||||||
|
HTTPException
|
||||||
|
Deleting the messages failed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
messages = list(messages)
|
||||||
|
if len(messages) > 100 or len(messages) < 2:
|
||||||
|
raise ClientException('Can only delete messages in the range of [2, 100]')
|
||||||
|
|
||||||
|
message_ids = [m.id for m in messages]
|
||||||
|
channel = yield from self._get_channel()
|
||||||
|
|
||||||
|
yield from self._state.http.delete_messages(channel.id, message_ids)
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def purge(self, *, limit=100, check=None, before=None, after=None, around=None):
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Purges a list of messages that meet the criteria given by the predicate
|
||||||
|
``check``. If a ``check`` is not provided then all messages are deleted
|
||||||
|
without discrimination.
|
||||||
|
|
||||||
|
You must have :attr:`Permissions.manage_messages` permission to delete
|
||||||
|
messages even if they are your own (unless you are a user account).
|
||||||
|
The :attr:`Permissions.read_message_history` permission is also needed
|
||||||
|
to retrieve message history.
|
||||||
|
|
||||||
|
Internally, this employs a different number of strategies depending
|
||||||
|
on the conditions met such as if a bulk delete is possible or if
|
||||||
|
the account is a user bot or not.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
limit: int
|
||||||
|
The number of messages to search through. This is not the number
|
||||||
|
of messages that will be deleted, though it can be.
|
||||||
|
check: predicate
|
||||||
|
The function used to check if a message should be deleted.
|
||||||
|
It must take a :class:`Message` as its sole parameter.
|
||||||
|
before
|
||||||
|
Same as ``before`` in :meth:`history`.
|
||||||
|
after
|
||||||
|
Same as ``after`` in :meth:`history`.
|
||||||
|
around
|
||||||
|
Same as ``around`` in :meth:`history`.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
-------
|
||||||
|
Forbidden
|
||||||
|
You do not have proper permissions to do the actions required.
|
||||||
|
HTTPException
|
||||||
|
Purging the messages failed.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
---------
|
||||||
|
|
||||||
|
Deleting bot's messages ::
|
||||||
|
|
||||||
|
def is_me(m):
|
||||||
|
return m.author == client.user
|
||||||
|
|
||||||
|
deleted = await channel.purge(limit=100, check=is_me)
|
||||||
|
await channel.send_message('Deleted {} message(s)'.format(len(deleted)))
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
list
|
||||||
|
The list of messages that were deleted.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if check is None:
|
||||||
|
check = lambda m: True
|
||||||
|
|
||||||
|
iterator = self.history(limit=limit, before=before, after=after, around=around)
|
||||||
|
ret = []
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
minimum_time = int((time.time() - 14 * 24 * 60 * 60) * 1000.0 - 1420070400000) << 22
|
||||||
|
strategy = self.delete_messages if self._state.is_bot else _single_delete_strategy
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
msg = yield from iterator.get()
|
||||||
|
except NoMoreItems:
|
||||||
|
# no more messages to poll
|
||||||
|
if count >= 2:
|
||||||
|
# more than 2 messages -> bulk delete
|
||||||
|
to_delete = ret[-count:]
|
||||||
|
yield from strategy(to_delete)
|
||||||
|
elif count == 1:
|
||||||
|
# delete a single message
|
||||||
|
yield from ret[-1].delete()
|
||||||
|
|
||||||
|
return ret
|
||||||
|
else:
|
||||||
|
if count == 100:
|
||||||
|
# we've reached a full 'queue'
|
||||||
|
to_delete = ret[-100:]
|
||||||
|
yield from strategy(to_delete)
|
||||||
|
count = 0
|
||||||
|
yield from asyncio.sleep(1)
|
||||||
|
|
||||||
|
if check(msg):
|
||||||
|
if msg.id < minimum_time:
|
||||||
|
# older than 14 days old
|
||||||
|
if count == 1:
|
||||||
|
yield from ret[-1].delete()
|
||||||
|
elif count >= 2:
|
||||||
|
to_delete = ret[-count:]
|
||||||
|
yield from strategy(to_delete)
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
strategy = _single_delete_strategy
|
||||||
|
|
||||||
|
count += 1
|
||||||
|
ret.append(msg)
|
||||||
|
|
||||||
class VoiceChannel(discord.abc.GuildChannel, Hashable):
|
class VoiceChannel(discord.abc.GuildChannel, Hashable):
|
||||||
"""Represents a Discord guild voice channel.
|
"""Represents a Discord guild voice channel.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user