From fb70f435087a09c02da62bff3063f45b4b8e054c Mon Sep 17 00:00:00 2001 From: Andrei Date: Fri, 16 Jun 2017 23:55:02 -0700 Subject: [PATCH] Checkpoint progress --- disco/api/client.py | 25 +++++++--- disco/api/http.py | 1 + disco/types/channel.py | 2 +- disco/types/guild.py | 104 ++++++++++++++++++++++++++++++++++++++- disco/types/invite.py | 13 ++--- disco/util/functional.py | 3 ++ examples/basic_plugin.py | 7 +++ 7 files changed, 137 insertions(+), 18 deletions(-) diff --git a/disco/api/client.py b/disco/api/client.py index d3df9bf..26fdc1d 100644 --- a/disco/api/client.py +++ b/disco/api/client.py @@ -2,13 +2,14 @@ import six import json import warnings +from six.moves.urllib.parse import quote + from disco.api.http import Routes, HTTPClient from disco.util.logging import LoggingClass from disco.util.sanitize import S - from disco.types.user import User from disco.types.message import Message -from disco.types.guild import Guild, GuildMember, GuildBan, Role, GuildEmoji +from disco.types.guild import Guild, GuildMember, GuildBan, Role, GuildEmoji, AuditLogEntry from disco.types.channel import Channel from disco.types.invite import Invite from disco.types.webhook import Webhook @@ -25,7 +26,7 @@ def optional(**kwargs): def _reason_header(value): - return optional(**{'X-Audit-Log-Reason': value}) + return optional(**{'X-Audit-Log-Reason': quote(value)}) class APIClient(LoggingClass): @@ -190,20 +191,20 @@ class APIClient(LoggingClass): 'type': typ, }, headers=_reason_header(reason)) - def channels_permissions_delete(self, channel, permission): - self.http(Routes.CHANNELS_PERMISSIONS_DELETE, dict(channel=channel, permission=permission)) + def channels_permissions_delete(self, channel, permission, reason=None): + self.http(Routes.CHANNELS_PERMISSIONS_DELETE, dict(channel=channel, permission=permission), headers=_reason_header(reason)) def channels_invites_list(self, channel): r = self.http(Routes.CHANNELS_INVITES_LIST, dict(channel=channel)) return Invite.create_map(self.client, r.json()) - def channels_invites_create(self, channel, max_age=86400, max_uses=0, temporary=False, unique=False): + def channels_invites_create(self, channel, max_age=86400, max_uses=0, temporary=False, unique=False, reason=None): r = self.http(Routes.CHANNELS_INVITES_CREATE, dict(channel=channel), json={ 'max_age': max_age, 'max_uses': max_uses, 'temporary': temporary, 'unique': unique - }) + }, headers=_reason_header(reason)) return Invite.create(self.client, r.json()) def channels_pins_list(self, channel): @@ -380,6 +381,16 @@ class APIClient(LoggingClass): dict(guild=guild, emoji=emoji), headers=_reason_header(reason)) + def guilds_auditlogs_list(self, guild, before, user_id=None, action_type=None, limit=50): + r = self.http(Routes.GUILDS, dict(guild=guild), json=optional( + before=before, + user_id=user_id, + action_type=action_type, + limit=limit, + )) + + return AuditLogEntry.create_map(self.client, r.json()['audit_log_entries']) + def users_me_get(self): return User.create(self.client, self.http(Routes.USERS_ME_GET).json()) diff --git a/disco/api/http.py b/disco/api/http.py index 462ad8e..fb85015 100644 --- a/disco/api/http.py +++ b/disco/api/http.py @@ -102,6 +102,7 @@ class Routes(object): GUILDS_EMOJIS_CREATE = (HTTPMethod.POST, GUILDS + '/emojis') GUILDS_EMOJIS_MODIFY = (HTTPMethod.PATCH, GUILDS + '/emojis/{emoji}') GUILDS_EMOJIS_DELETE = (HTTPMethod.DELETE, GUILDS + '/emojis/{emoji}') + GUILDS_AUDITLOGS_LIST = (HTTPMethod.GET, GUILDS + '/audit-logs') # Users USERS = '/users' diff --git a/disco/types/channel.py b/disco/types/channel.py index 14dedc3..1b99f8b 100644 --- a/disco/types/channel.py +++ b/disco/types/channel.py @@ -232,7 +232,7 @@ class Channel(SlottedModel, Permissible): def create_invite(self, *args, **kwargs): from disco.types.invite import Invite - return Invite.create(self, *args, **kwargs) + return Invite.create_for_channel(self, *args, **kwargs) def get_pins(self): """ diff --git a/disco/types/guild.py b/disco/types/guild.py index 594d56a..6f27faa 100644 --- a/disco/types/guild.py +++ b/disco/types/guild.py @@ -7,7 +7,7 @@ from disco.api.http import APIException from disco.util.snowflake import to_snowflake from disco.util.functional import cached_property from disco.types.base import ( - SlottedModel, Field, ListField, AutoDictField, snowflake, text, binary, enum, datetime + SlottedModel, Field, ListField, AutoDictField, DictField, snowflake, text, binary, enum, datetime ) from disco.types.user import User from disco.types.voice import VoiceState @@ -448,3 +448,105 @@ class Guild(SlottedModel, Permissible): def get_emojis(self): return self.client.api.guilds_emojis_list(self.id) + + +AuditLogActionTypes = Enum( + GUILD_UPDATE=1, + CHANNEL_CREATE=10, + CHANNEL_UPDATE=11, + CHANNEL_DELETE=12, + CHANNEL_OVERWRITE_CREATE=13, + CHANNEL_OVERWRITE_UPDATE=14, + CHANNEL_OVERWRITE_DELETE=15, + MEMBER_KICK=20, + MEMBER_PRUNE=21, + MEMBER_BAN_ADD=22, + MEMBER_BAN_REMOVE=23, + MEMBER_UPDATE=24, + MEMBER_ROLE_UPDATE=25, + ROLE_CREATE=30, + ROLE_UPDATE=31, + ROLE_DELETE=32, + INVITE_CREATE=40, + INVITE_UPDATE=41, + INVITE_DELETE=42, + WEBHOOK_CREATE=50, + WEBHOOK_UPDATE=51, + WEBHOOK_DELETE=52, + EMOJI_CREATE=60, + EMOJI_UPDATE=61, + EMOJI_DELETE=62, + MESSAGE_DELETE=72, +) + + +GUILD_ACTIONS = ( + AuditLogActionTypes.GUILD_UPDATE, +) + +CHANNEL_ACTIONS = ( + AuditLogActionTypes.CHANNEL_CREATE, + AuditLogActionTypes.CHANNEL_UPDATE, + AuditLogActionTypes.CHANNEL_DELETE, + AuditLogActionTypes.CHANNEL_OVERWRITE_CREATE, + AuditLogActionTypes.CHANNEL_OVERWRITE_UPDATE, + AuditLogActionTypes.CHANNEL_OVERWRITE_DELETE, +) + +MEMBER_ACTIONS = ( + AuditLogActionTypes.MEMBER_KICK, + AuditLogActionTypes.MEMBER_PRUNE, + AuditLogActionTypes.MEMBER_BAN_ADD, + AuditLogActionTypes.MEMBER_BAN_REMOVE, + AuditLogActionTypes.MEMBER_UPDATE, + AuditLogActionTypes.MEMBER_ROLE_UPDATE, +) + +ROLE_ACTIONS = ( + AuditLogActionTypes.ROLE_CREATE, + AuditLogActionTypes.ROLE_UPDATE, + AuditLogActionTypes.ROLE_DELETE, +) + +INVITE_ACTIONS = ( + AuditLogActionTypes.INVITE_CREATE, + AuditLogActionTypes.INVITE_UPDATE, + AuditLogActionTypes.INVITE_DELETE, +) + +WEBHOOK_ACTIONS = ( + AuditLogActionTypes.WEBHOOK_CREATE, + AuditLogActionTypes.WEBHOOK_UPDATE, + AuditLogActionTypes.WEBHOOK_DELETE, +) + +EMOJI_ACTIONS = ( + AuditLogActionTypes.EMOJI_CREATE, + AuditLogActionTypes.EMOJI_UPDATE, + AuditLogActionTypes.EMOJI_DELETE, +) + +MESSAGE_ACTIONS = ( + AuditLogActionTypes.MESSAGE_DELETE, +) + + +class AuditLogObjectChange(SlottedModel): + key = Field(text) + new_value = Field(text) + old_value = Field(text) + + +class AuditLogEntry(SlottedModel): + id = Field(snowflake) + guild = Field(None) + user_id = Field(snowflake) + target_id = Field(snowflake) + action_type = Field(enum(AuditLogActionTypes)) + changes = ListField(AuditLogObjectChange) + options = DictField(text, text) + reason = Field(text) + + @cached_property + def user(self): + return self.client.state.users.get(self.user_id) diff --git a/disco/types/invite.py b/disco/types/invite.py index 7f22a57..1b458ef 100644 --- a/disco/types/invite.py +++ b/disco/types/invite.py @@ -40,13 +40,8 @@ class Invite(SlottedModel): created_at = Field(datetime) @classmethod - def create_for_channel(cls, channel, max_age=86400, max_uses=0, temporary=False, unique=False): - return channel.client.api.channels_invites_create( - channel.id, - max_age=max_age, - max_uses=max_uses, - temporary=temporary, - unique=unique) + def create_for_channel(cls, channel, *args, **kwargs): + return channel.client.api.channels_invites_create(channel.id, *args, **kwargs) - def delete(self): - self.client.api.invites_delete(self.code) + def delete(self, *args, **kwargs): + self.client.api.invites_delete(self.code, *args, **kwargs) diff --git a/disco/util/functional.py b/disco/util/functional.py index ee0ac02..5050842 100644 --- a/disco/util/functional.py +++ b/disco/util/functional.py @@ -56,6 +56,9 @@ class CachedSlotProperty(object): self.function = function self.__doc__ = getattr(function, '__doc__') + def set(self, value): + setattr(self.stored_name, value) + def __get__(self, instance, owner): if instance is None: return self diff --git a/examples/basic_plugin.py b/examples/basic_plugin.py index 6209d4b..40b01d6 100644 --- a/examples/basic_plugin.py +++ b/examples/basic_plugin.py @@ -2,6 +2,13 @@ from disco.bot import Plugin class BasicPlugin(Plugin): + @Plugin.command('auditme') + def on_auditme(self, event): + invite = event.channel.create_invite(reason='TEST AUDIT') + invite.delete(reason='TEST AUDIT 2') + # channel = event.guild.create_channel('audit-log-test', 'text', reason='TEST CREATE') + # channel.delete(reason='TEST AUDIT 2') + @Plugin.command('reload') def on_reload(self, event): self.reload()