From b7da8b83ef1353b4dc5e28a7cd8f1509fc463b24 Mon Sep 17 00:00:00 2001 From: Andrei Date: Thu, 22 Sep 2016 18:34:35 -0500 Subject: [PATCH] More API stuff --- disco/api/client.py | 68 ++++++++++++++++++++++++++++++++-------- disco/api/http.py | 68 +++++++++++++++++++++++++++++++++++++--- disco/types/base.py | 16 +++++++++- disco/types/channel.py | 5 +-- disco/types/message.py | 8 ++++- examples/basic_plugin.py | 2 +- 6 files changed, 144 insertions(+), 23 deletions(-) diff --git a/disco/api/client.py b/disco/api/client.py index 81a69ee..77e3eb7 100644 --- a/disco/api/client.py +++ b/disco/api/client.py @@ -1,7 +1,13 @@ from disco.api.http import Routes, HTTPClient - from disco.util.logging import LoggingClass +from disco.types.message import Message +from disco.types.channel import Channel + + +def optional(**kwargs): + return {k: v for k, v in kwargs if v is not None} + class APIClient(LoggingClass): def __init__(self, client): @@ -11,15 +17,51 @@ class APIClient(LoggingClass): self.http = HTTPClient(self.client.token) def gateway(self, version, encoding): - r = self.http(Routes.GATEWAY_GET) - return r['url'] + '?v={}&encoding={}'.format(version, encoding) - - def channels_messages_send(self, channel, content, nonce=None, tts=False): - r = self.http(Routes.CHANNELS_MESSAGES_POST, channel, json={ - 'content': content, - 'nonce': nonce, - 'tts': tts, - }) - - # TODO: return correct types - return r + data = self.http(Routes.GATEWAY_GET).json() + return data['url'] + '?v={}&encoding={}'.format(version, encoding) + + def channels_get(self, channel): + r = self.http(Routes.CHANNELS_GET, channel) + return Channel.create(self.client, r.json()) + + def channels_modify(self, channel, **kwargs): + r = self.http(Routes.CHANNELS_MODIFY, channel, json=kwargs) + return Channel.create(self.client, r.json()) + + def channels_delete(self, channel): + r = self.http(Routes.CHANNELS_DELETE, channel) + return Channel.create(self.client, r.json()) + + def channels_messages_list(self, channel, around=None, before=None, after=None, limit=50): + r = self.http(Routes.CHANNELS_MESSAGES_LIST, channel, json=optional( + channel=channel, + around=around, + before=before, + after=after, + limit=limit + )) + + return [Message.create(self.client, i) for i in r.json()] + + def channels_messages_get(self, channel, message): + r = self.http(Routes.CHANNELS_MESSAGES_GET, channel, message) + return Message.create(self.client, r.json()) + + def channels_messages_create(self, channel, content, nonce=None, tts=False): + r = self.http(Routes.CHANNELS_MESSAGES_CREATE, channel, json={ + 'content': content, + 'nonce': nonce, + 'tts': tts, + }) + + return Message.create(self.client, r.json()) + + def channels_messages_modify(self, channel, message, content): + r = self.http(Routes.CHANNELS_MESSAGES_MODIFY, channel, message, json={'content': content}) + return Message.create(self.client, r.json()) + + def channels_messages_delete(self, channel, message): + self.http(Routes.CHANNELS_MESSAGES_DELETE, channel, message) + + def channels_messages_delete_bulk(self, channel, messages): + self.http(Routes.CHANNELS_MESSAGES_DELETE_BULK, channel, json={'messages': messages}) diff --git a/disco/api/http.py b/disco/api/http.py index 93a7b37..bd5df9d 100644 --- a/disco/api/http.py +++ b/disco/api/http.py @@ -15,12 +15,70 @@ HTTPMethod = Enum( class Routes(object): - USERS_ME_GET = (HTTPMethod.GET, '/users/@me') - USERS_ME_PATCH = (HTTPMethod.PATCH, '/users/@me') - + # Gateway GATEWAY_GET = (HTTPMethod.GET, '/gateway') - CHANNELS_MESSAGES_POST = (HTTPMethod.POST, '/channels/{}/messages') + # Channels + CHANNELS_GET = (HTTPMethod.GET, '/channels/{}') + CHANNELS_MODIFY= (HTTPMethod.PATCH, '/channels/{}') + CHANNELS_DELETE = (HTTPMethod.DELETE, '/channels/{}') + + CHANNELS_MESSAGES_LIST = (HTTPMethod.GET, '/channels/{}/messages') + CHANNELS_MESSAGES_GET = (HTTPMethod.GET, '/channels/{}/messages/{}') + CHANNELS_MESSAGES_CREATE = (HTTPMethod.POST, '/channels/{}/messages') + CHANNELS_MESSAGES_MODFIY = (HTTPMethod.PATCH, '/channels/{}/messages/{}') + CHANNELS_MESSAGES_DELETE = (HTTPMethod.DELETE, '/channels/{}/messages/{}') + CHANNELS_MESSAGES_DELETE_BULK = (HTTPMethod.POST, '/channels/{}/messages/bulk_delete') + + CHANNELS_PERMISSIONS_MODIFY = (HTTPMethod.PUT, '/channels/{}/permissions/{}') + CHANNELS_PERMISSIONS_DELETE = (HTTPMethod.DELETE, '/channels/{}/permissions/{}') + CHANNELS_INVITES_LIST = (HTTPMethod.GET, '/channels/{}/invites') + CHANNELS_INVITES_CREATE = (HTTPMethod.POST, '/channels/{}/invites') + + CHANNELS_PINS_LIST = (HTTPMethod.GET, '/channels/{}/pins') + CHANNELS_PINS_CREATE = (HTTPMethod.PUT, '/channels/{}/pins/{}') + CHANNELS_PINS_DELETE = (HTTPMethod.DELETE, '/channels/{}/pins/{}') + + # Guilds + GUILDS_GET = (HTTPMethod.GET, '/guilds/{}') + GUILDS_MODIFY = (HTTPMethod.PATCH, '/guilds/{}') + GUILDS_DELETE = (HTTPMethod.DELETE, '/guilds/{}') + GUILDS_CHANNELS_LIST = (HTTPMethod.GET, '/guilds/{}/channels') + GUILDS_CHANNELS_CREATE = (HTTPMethod.POST, '/guilds/{}/channels') + GUILDS_CHANNELS_MODIFY = (HTTPMethod.PATCH, '/guilds/{}/channels') + GUILDS_MEMBERS_LIST = (HTTPMethod.GET, '/guilds/{}/members') + GUILDS_MEMBERS_GET = (HTTPMethod.GET, '/guilds/{}/members/{}') + GUILDS_MEMBERS_MODIFY = (HTTPMethod.PATCH, '/guilds/{}/members/{}') + GUILDS_MEMBERS_KICK = (HTTPMethod.DELETE, '/guilds/{}/members/{}') + GUILDS_BANS_LIST = (HTTPMethod.GET, '/guilds/{}/bans') + GUILDS_BANS_CREATE = (HTTPMethod.PUT, '/guilds/{}/bans/{}') + GUILDS_BANS_DELETE = (HTTPMethod.DELETE, '/guilds/{}/bans/{}') + GUILDS_ROLES_LIST = (HTTPMethod.GET, '/guilds/{}/roles') + GUILDS_ROLES_CREATE = (HTTPMethod.GET, '/guilds/{}/roles') + GUILDS_ROLES_MODIFY_BATCH = (HTTPMethod.PATCH, '/guilds/{}/roles') + GUILDS_ROLES_MODIFY = (HTTPMethod.PATCH, '/guilds/{}/roles/{}') + GUILDS_ROLES_DELETE = (HTTPMethod.DELETE, '/guilds/{}/roles/{}') + GUILDS_PRUNE_COUNT = (HTTPMethod.GET, '/guilds/{}/prune') + GUILDS_PRUNE_BEGIN = (HTTPMethod.POST, '/guilds/{}/prune') + GUILDS_VOICE_REGIONS_LIST = (HTTPMethod.GET, '/guilds/{}/regions') + GUILDS_INVITES_LIST = (HTTPMethod.GET, '/guilds/{}/invites') + GUILDS_INTEGRATIONS_LIST = (HTTPMethod.GET, '/guilds/{}/integrations') + GUILDS_INTEGRATIONS_CREATE = (HTTPMethod.POST, '/guilds/{}/integrations') + GUILDS_INTEGRATIONS_MODIFY = (HTTPMethod.PATCH, '/guilds/{}/integrations/{}') + GUILDS_INTEGRATIONS_DELETE = (HTTPMethod.DELETE, '/guilds/{}/integrations/{}') + GUILDS_INTEGRATIONS_SYNC = (HTTPMethod.POST, '/guilds/{}/integrations/{}/sync') + GUILDS_EMBED_GET = (HTTPMethod.GET, '/guilds/{}/embed') + GUILDS_EMBED_MODIFY = (HTTPMethod.PATCH, '/guilds/{}/embed') + + # Users + USERS_ME_GET = (HTTPMethod.GET, '/users/@me') + USERS_ME_PATCH = (HTTPMethod.PATCH, '/users/@me') + USERS_ME_GUILDS_LIST = (HTTPMethod.GET, '/users/@me/guilds') + USERS_ME_GUILDS_LEAVE = (HTTPMethod.DELETE, '/users/@me/guilds/{}') + USERS_ME_DMS_LIST = (HTTPMethod.GET, '/users/@me/channels') + USERS_ME_DMS_CREATE = (HTTPMethod.POST, '/users/@me/channels') + USERS_ME_CONNECTIONS_LIST = (HTTPMethod.GET, '/users/@me/connections') + USERS_GET = (HTTPMethod.GET, '/users/{}') class APIException(Exception): @@ -65,7 +123,7 @@ class HTTPClient(LoggingClass): # If we got a success status code, just return the data if r.status_code < 400: - return r.json() + return r else: if r.status_code == 429: self.log.warning('Request responded w/ 429, retrying (but this should not happen, check your clock sync') diff --git a/disco/types/base.py b/disco/types/base.py index fb590a9..78bad1e 100644 --- a/disco/types/base.py +++ b/disco/types/base.py @@ -1,5 +1,19 @@ import skema +from disco.util import recursive_find_matching + class BaseType(skema.Model): - pass + @classmethod + def create(cls, client, data): + obj = cls(data) + + # Valdiate + obj.validate() + + # TODO: this can be smarter using skema metadata + for item in recursive_find_matching(obj, lambda v: isinstance(v, BaseType)): + item.client = client + + obj.client = client + return obj diff --git a/disco/types/channel.py b/disco/types/channel.py index abbf1f6..b404f2b 100644 --- a/disco/types/channel.py +++ b/disco/types/channel.py @@ -45,6 +45,7 @@ class Channel(BaseType): @cached_property def guild(self): - print self.guild_id - print self.client.state.guilds return self.client.state.guilds.get(self.guild_id) + + def send_message(self, content, nonce=None, tts=False): + return self.client.api.channels_messages_create(self.id, content, nonce, tts) diff --git a/disco/types/message.py b/disco/types/message.py index 818fbc7..21c2490 100644 --- a/disco/types/message.py +++ b/disco/types/message.py @@ -64,7 +64,13 @@ class Message(BaseType): return {i.id: i for i in self.mentions} def reply(self, *args, **kwargs): - return self.client.api.channels_messages_send(self.channel_id, *args, **kwargs) + return self.channel.send_message(*args, **kwargs) + + def edit(self, content): + return self.client.api.channels_messages_modify(self.channel_id, self.id, content) + + def delete(self, content): + return self.client.api.channels_messages_delete(self.channel_id, self.id) def is_mentioned(self, entity): if isinstance(entity, User): diff --git a/examples/basic_plugin.py b/examples/basic_plugin.py index 9df21f3..2d5df1d 100644 --- a/examples/basic_plugin.py +++ b/examples/basic_plugin.py @@ -17,7 +17,7 @@ class BasicPlugin(Plugin): count = int(event.args[0]) for i in range(count): - event.msg.reply(' '.join(event.args[1:])) + print event.msg.reply(' '.join(event.args[1:])).id if __name__ == '__main__': bot = Bot(disco_main())