Add friendly method to get admin log (#952)

This commit is contained in:
Lonami Exo 2019-01-03 13:09:59 +01:00
parent 95cf873bad
commit 4ccabaf422
3 changed files with 445 additions and 1 deletions

View File

@ -1,8 +1,11 @@
import itertools
import sys
from async_generator import async_generator, yield_
from .users import UserMethods
from .. import utils, helpers
from ..tl import types, functions
from ..tl import types, functions, custom
class ChatMethods(UserMethods):
@ -188,4 +191,150 @@ class ChatMethods(UserMethods):
participants.total = total[0]
return participants
@async_generator
async def iter_admin_log(
self, entity, limit=None, *, max_id=0, min_id=0, search=None,
admins=None, join=None, leave=None, invite=None, restrict=None,
unrestrict=None, ban=None, unban=None, promote=None, demote=None,
info=None, settings=None, pinned=None, edit=None, delete=None):
"""
Iterator over the admin log for the specified channel.
Note that you must be an administrator of it to use this method.
If none of the filters are present (i.e. they all are ``None``),
*all* event types will be returned. If at least one of them is
``True``, only those that are true will be returned.
Args:
entity (`entity`):
The channel entity from which to get its admin log.
limit (`int` | `None`, optional):
Number of events to be retrieved.
The limit may also be ``None``, which would eventually return
the whole history.
max_id (`int`):
All the events with a higher (newer) ID or equal to this will
be excluded.
min_id (`int`):
All the events with a lower (older) ID or equal to this will
be excluded.
search (`str`):
The string to be used as a search query.
admins (`entity` | `list`):
If present, the events will be filtered by these admins
(or single admin) and only those caused by them will be
returned.
join (`bool`):
If ``True``, events for when a user joined will be returned.
leave (`bool`):
If ``True``, events for when a user leaves will be returned.
invite (`bool`):
If ``True``, events for when a user joins through an invite
link will be returned.
restrict (`bool`):
If ``True``, events with partial restrictions will be
returned. This is what the API calls "ban".
unrestrict (`bool`):
If ``True``, events removing restrictions will be returned.
This is what the API calls "unban".
ban (`bool`):
If ``True``, events applying or removing all restrictions will
be returned. This is what the API calls "kick" (restricting
all permissions removed is a ban, which kicks the user).
unban (`bool`):
If ``True``, events removing all restrictions will be
returned. This is what the API calls "unkick".
promote (`bool`):
If ``True``, events with admin promotions will be returned.
demote (`bool`):
If ``True``, events with admin demotions will be returned.
info (`bool`):
If ``True``, events changing the group info will be returned.
settings (`bool`):
If ``True``, events changing the group settings will be
returned.
pinned (`bool`):
If ``True``, events of new pinned messages will be returned.
edit (`bool`):
If ``True``, events of message edits will be returned.
delete (`bool`):
If ``True``, events of message deletions will be returned.
Yields:
Instances of `telethon.tl.custom.adminlogevent.AdminLogEvent`.
"""
if limit is None:
limit = sys.maxsize
elif limit <= 0:
return
if any((join, leave, invite, restrict, unrestrict, ban, unban,
promote, demote, info, settings, pinned, edit, delete)):
events_filter = types.ChannelAdminLogEventsFilter(
join=join, leave=leave, invite=invite, ban=restrict,
unban=unrestrict, kick=ban, unkick=unban, promote=promote,
demote=demote, info=info, settings=settings, pinned=pinned,
edit=edit, delete=delete
)
else:
events_filter = None
entity = await self.get_input_entity(entity)
admin_list = []
if admins:
if not utils.is_list_like(admins):
admins = (admins,)
for admin in admins:
admin_list.append(await self.get_input_entity(admin))
request = functions.channels.GetAdminLogRequest(
entity, q=search or '', min_id=min_id, max_id=max_id,
limit=0, events_filter=events_filter, admins=admin_list or None
)
while limit > 0:
request.limit = min(limit, 100)
result = await self(request)
limit -= len(result.events)
entities = {utils.get_peer_id(x): x
for x in itertools.chain(result.users, result.chats)}
request.max_id = min((e.id for e in result.events), default=0)
for event in result.events:
await yield_(custom.AdminLogEvent(event, entities))
if len(result.events) < request.limit:
break
async def get_admin_log(self, *args, **kwargs):
"""
Same as `iter_admin_log`, but returns a ``list`` instead.
"""
admin_log = []
async for x in self.iter_admin_log(*args, **kwargs):
admin_log.append(x)
return admin_log
# endregion

View File

@ -1,3 +1,4 @@
from .adminlogevent import AdminLogEvent
from .draft import Draft
from .dialog import Dialog
from .inputsizedfile import InputSizedFile

View File

@ -0,0 +1,294 @@
from ...tl import types
from ...utils import get_input_peer
class AdminLogEvent:
"""
Represents a more friendly interface for admin log events.
Members:
original (:tl:`ChannelAdminLogEvent`):
The original :tl:`ChannelAdminLogEvent`.
entities (`dict`):
A dictionary mapping user IDs to :tl:`User`.
When `old` and `new` are :tl:`ChannelParticipant`, you can
use this dictionary to map the ``user_id``, ``kicked_by``,
``inviter_id`` and ``promoted_by`` IDs to their :tl:`User`.
user (:tl:`User`):
The user that caused this action (``entities[original.user_id]``).
input_user (:tl:`InputPeerUser`):
Input variant of `user`.
"""
def __init__(self, original, entities):
self.original = original
self.entities = entities
self.user = entities[original.user_id]
self.input_user = get_input_peer(self.user)
@property
def id(self):
"""
The ID of this event.
"""
return self.original.id
@property
def date(self):
"""
The date when this event occured.
"""
return self.original.date
@property
def user_id(self):
"""
The ID of the user that triggered this event.
"""
return self.original.user_id
@property
def action(self):
"""
The original :tl:`ChannelAdminLogEventAction`.
"""
return self.original.action
@property
def old(self):
"""
The old value from the event.
"""
ori = self.original
if isinstance(ori, (
types.ChannelAdminLogEventActionChangeAbout,
types.ChannelAdminLogEventActionChangeTitle,
types.ChannelAdminLogEventActionChangeUsername
)):
return ori.prev_value
elif isinstance(ori, types.ChannelAdminLogEventActionChangePhoto):
return ori.prev_photo
elif isinstance(ori, types.ChannelAdminLogEventActionChangeStickerSet):
return ori.prev_stickerset
elif isinstance(ori, types.ChannelAdminLogEventActionEditMessage):
return ori.prev_message
elif isinstance(ori, (
types.ChannelAdminLogEventActionParticipantToggleAdmin,
types.ChannelAdminLogEventActionParticipantToggleBan
)):
return ori.prev_participant
elif isinstance(ori, (
types.ChannelAdminLogEventActionToggleInvites,
types.ChannelAdminLogEventActionTogglePreHistoryHidden,
types.ChannelAdminLogEventActionToggleSignatures
)):
return not ori.new_value
elif isinstance(ori, types.ChannelAdminLogEventActionDeleteMessage):
return ori.message
@property
def new(self):
"""
The new value present in the event.
"""
ori = self.original
if isinstance(ori, (
types.ChannelAdminLogEventActionChangeAbout,
types.ChannelAdminLogEventActionChangeTitle,
types.ChannelAdminLogEventActionChangeUsername,
types.ChannelAdminLogEventActionToggleInvites,
types.ChannelAdminLogEventActionTogglePreHistoryHidden,
types.ChannelAdminLogEventActionToggleSignatures
)):
return ori.new_value
elif isinstance(ori, types.ChannelAdminLogEventActionChangePhoto):
return ori.new_photo
elif isinstance(ori, types.ChannelAdminLogEventActionChangeStickerSet):
return ori.new_stickerset
elif isinstance(ori, types.ChannelAdminLogEventActionEditMessage):
return ori.new_message
elif isinstance(ori, (
types.ChannelAdminLogEventActionParticipantToggleAdmin,
types.ChannelAdminLogEventActionParticipantToggleBan
)):
return ori.new_participant
elif isinstance(ori, types.ChannelAdminLogEventActionParticipantInvite):
return ori.participant
@property
def changed_about(self):
"""
Whether the channel's about was changed in this event or not.
If ``True``, `old` and `new` will be present as ``str``.
"""
return isinstance(self.original,
types.ChannelAdminLogEventActionChangeAbout)
@property
def changed_title(self):
"""
Whether the channel's title was changed in this event or not.
If ``True``, `old` and `new` will be present as ``str``.
"""
return isinstance(self.original,
types.ChannelAdminLogEventActionChangeTitle)
@property
def changed_username(self):
"""
Whether the channel's username was changed in this event or not.
If ``True``, `old` and `new` will be present as ``str``.
"""
return isinstance(self.original,
types.ChannelAdminLogEventActionChangeUsername)
@property
def changed_photo(self):
"""
Whether the channel's photo was changed in this event or not.
If ``True``, `old` and `new` will be present as :tl:`ChatPhoto`.
"""
return isinstance(self.original,
types.ChannelAdminLogEventActionChangePhoto)
@property
def changed_sticker_set(self):
"""
Whether the channel's sticker set was changed in this event or not.
If ``True``, `old` and `new` will be present as :tl:`InputStickerSet`.
"""
return isinstance(self.original,
types.ChannelAdminLogEventActionChangeStickerSet)
@property
def changed_message(self):
"""
Whether a message in this channel was edited in this event or not.
If ``True``, `old` and `new` will be present as
`Message <telethon.tl.custom.message.Message>`.
"""
return isinstance(self.original,
types.ChannelAdminLogEventActionEditMessage)
@property
def deleted_message(self):
"""
Whether a message in this channel was deleted in this event or not.
If ``True``, `old` will be present as
`Message <telethon.tl.custom.message.Message>`.
"""
return isinstance(self.original,
types.ChannelAdminLogEventActionDeleteMessage)
@property
def changed_admin(self):
"""
Whether the permissions for an admin in this channel
changed in this event or not.
If ``True``, `old` and `new` will be present as
:tl:`ChannelParticipant`.
"""
return isinstance(
self.original,
types.ChannelAdminLogEventActionParticipantToggleAdmin)
@property
def changed_restrictions(self):
"""
Whether a message in this channel was edited in this event or not.
If ``True``, `old` and `new` will be present as
:tl:`ChannelParticipant`.
"""
return isinstance(
self.original,
types.ChannelAdminLogEventActionParticipantToggleBan)
@property
def changed_invites(self):
"""
Whether the invites in the channel were toggled in this event or not.
If ``True``, `old` and `new` will be present as ``bool``.
"""
return isinstance(self.original,
types.ChannelAdminLogEventActionToggleInvites)
@property
def joined(self):
"""
Whether `user` joined through the channel's
public username in this event or not.
"""
return isinstance(self.original,
types.ChannelAdminLogEventActionParticipantJoin)
@property
def joined_invite(self):
"""
Whether a new user joined through an invite
link to the channel in this event or not.
If ``True``, `new` will be present as
:tl:`ChannelParticipant`.
"""
return isinstance(self.original,
types.ChannelAdminLogEventActionParticipantInvite)
@property
def left(self):
"""
Whether `user` left the channel in this event or not.
"""
return isinstance(self.original,
types.ChannelAdminLogEventActionParticipantLeave)
@property
def changed_hide_history(self):
"""
Whether hiding the previous message history for new members
in the channel were toggled in this event or not.
If ``True``, `old` and `new` will be present as ``bool``.
"""
return isinstance(self.original,
types.ChannelAdminLogEventActionTogglePreHistoryHidden)
@property
def changed_signatures(self):
"""
Whether the message signatures in the channel were toggled
in this event or not.
If ``True``, `old` and `new` will be present as ``bool``.
"""
return isinstance(self.original,
types.ChannelAdminLogEventActionToggleSignatures)
@property
def changed_pin(self):
"""
Whether a new message in this channel was pinned in this event or not.
If ``True``, `new` will be present as
`Message <telethon.tl.custom.message.Message>`.
"""
return isinstance(self.original,
types.ChannelAdminLogEventActionUpdatePinned)
def __str__(self):
return str(self.original)
def stringify(self):
return self.original.stringify()