Browse Source

Add webhooks

pull/8/head
Andrei 9 years ago
parent
commit
190100f50b
  1. 50
      disco/api/client.py
  2. 20
      disco/api/http.py
  3. 1
      disco/gateway/events.py
  4. 2
      disco/types/base.py
  5. 6
      disco/types/channel.py
  6. 50
      disco/types/message.py
  7. 43
      disco/types/webhook.py

50
disco/api/client.py

@ -8,6 +8,7 @@ from disco.types.message import Message
from disco.types.guild import Guild, GuildMember, Role from disco.types.guild import Guild, GuildMember, Role
from disco.types.channel import Channel from disco.types.channel import Channel
from disco.types.invite import Invite from disco.types.invite import Invite
from disco.types.webhook import Webhook
def optional(**kwargs): def optional(**kwargs):
@ -115,6 +116,17 @@ class APIClient(LoggingClass):
def channels_pins_delete(self, channel, message): def channels_pins_delete(self, channel, message):
self.http(Routes.CHANNELS_PINS_DELETE, dict(channel=channel, message=message)) self.http(Routes.CHANNELS_PINS_DELETE, dict(channel=channel, message=message))
def channels_webhooks_create(self, channel, name=None, avatar=None):
r = self.http(Routes.CHANNELS_WEBHOOKS_CREATE, dict(channel=channel), json=optional(
name=name,
avatar=avatar,
))
return Webhook.create(self.client, r.json())
def channels_webhooks_list(self, channel):
r = self.http(Routes.CHANNELS_WEBHOOKS_LIST, dict(channel=channel))
return Webhook.create_map(self.client, r.json())
def guilds_get(self, guild): def guilds_get(self, guild):
r = self.http(Routes.GUILDS_GET, dict(guild=guild)) r = self.http(Routes.GUILDS_GET, dict(guild=guild))
return Guild.create(self.client, r.json()) return Guild.create(self.client, r.json())
@ -186,6 +198,10 @@ class APIClient(LoggingClass):
def guilds_roles_delete(self, guild, role): def guilds_roles_delete(self, guild, role):
self.http(Routes.GUILDS_ROLES_DELETE, dict(guild=guild, role=role)) self.http(Routes.GUILDS_ROLES_DELETE, dict(guild=guild, role=role))
def guilds_webhooks_list(self, guild):
r = self.http(Routes.GUILDS_WEBHOOKS_LIST, dict(guild=guild))
return Webhook.create_map(self.client, r.json())
def invites_get(self, invite): def invites_get(self, invite):
r = self.http(Routes.INVITES_GET, dict(invite=invite)) r = self.http(Routes.INVITES_GET, dict(invite=invite))
return Invite.create(self.client, r.json()) return Invite.create(self.client, r.json())
@ -193,3 +209,37 @@ class APIClient(LoggingClass):
def invites_delete(self, invite): def invites_delete(self, invite):
r = self.http(Routes.INVITES_DELETE, dict(invite=invite)) r = self.http(Routes.INVITES_DELETE, dict(invite=invite))
return Invite.create(self.client, r.json()) return Invite.create(self.client, r.json())
def webhooks_get(self, webhook):
r = self.http(Routes.WEBHOOKS_GET, dict(webhook=webhook))
return Webhook.create(self.client, r.json())
def webhooks_modify(self, webhook, name=None, avatar=None):
r = self.http(Routes.WEBHOOKS_MODIFY, dict(webhook=webhook), json=optional(
name=name,
avatar=avatar,
))
return Webhook.create(self.client, r.json())
def webhooks_delete(self, webhook):
self.http(Routes.WEBHOOKS_DELETE, dict(webhook=webhook))
def webhooks_token_get(self, webhook, token):
r = self.http(Routes.WEBHOOKS_TOKEN_GET, dict(webhook=webhook, token=token))
return Webhook.create(self.client, r.json())
def webhooks_token_modify(self, webhook, token, name=None, avatar=None):
r = self.http(Routes.WEBHOOKS_TOKEN_MODIFY, dict(webhook=webhook, token=token), json=optional(
name=name,
avatar=avatar,
))
return Webhook.create(self.client, r.json())
def webhooks_token_delete(self, webhook, token):
self.http(Routes.WEBHOOKS_TOKEN_DLEETE, dict(webhook=webhook, token=token))
def webhooks_token_execute(self, webhook, token, data, wait=False):
self.http(
Routes.WEBHOOKS_TOKEN_EXECUTE,
dict(webhook=webhook, token=token),
json=optional(**data), params={'wait': int(wait)})

20
disco/api/http.py

@ -31,22 +31,21 @@ class Routes(object):
CHANNELS_GET = (HTTPMethod.GET, CHANNELS) CHANNELS_GET = (HTTPMethod.GET, CHANNELS)
CHANNELS_MODIFY = (HTTPMethod.PATCH, CHANNELS) CHANNELS_MODIFY = (HTTPMethod.PATCH, CHANNELS)
CHANNELS_DELETE = (HTTPMethod.DELETE, CHANNELS) CHANNELS_DELETE = (HTTPMethod.DELETE, CHANNELS)
CHANNELS_MESSAGES_LIST = (HTTPMethod.GET, CHANNELS + '/messages') CHANNELS_MESSAGES_LIST = (HTTPMethod.GET, CHANNELS + '/messages')
CHANNELS_MESSAGES_GET = (HTTPMethod.GET, CHANNELS + '/messages/{message}') CHANNELS_MESSAGES_GET = (HTTPMethod.GET, CHANNELS + '/messages/{message}')
CHANNELS_MESSAGES_CREATE = (HTTPMethod.POST, CHANNELS + '/messages') CHANNELS_MESSAGES_CREATE = (HTTPMethod.POST, CHANNELS + '/messages')
CHANNELS_MESSAGES_MODIFY = (HTTPMethod.PATCH, CHANNELS + '/messages/{message}') CHANNELS_MESSAGES_MODIFY = (HTTPMethod.PATCH, CHANNELS + '/messages/{message}')
CHANNELS_MESSAGES_DELETE = (HTTPMethod.DELETE, CHANNELS + '/messages/{message}') CHANNELS_MESSAGES_DELETE = (HTTPMethod.DELETE, CHANNELS + '/messages/{message}')
CHANNELS_MESSAGES_DELETE_BULK = (HTTPMethod.POST, CHANNELS + '/messages/bulk_delete') CHANNELS_MESSAGES_DELETE_BULK = (HTTPMethod.POST, CHANNELS + '/messages/bulk_delete')
CHANNELS_PERMISSIONS_MODIFY = (HTTPMethod.PUT, CHANNELS + '/permissions/{permission}') CHANNELS_PERMISSIONS_MODIFY = (HTTPMethod.PUT, CHANNELS + '/permissions/{permission}')
CHANNELS_PERMISSIONS_DELETE = (HTTPMethod.DELETE, CHANNELS + '/permissions/{permission}') CHANNELS_PERMISSIONS_DELETE = (HTTPMethod.DELETE, CHANNELS + '/permissions/{permission}')
CHANNELS_INVITES_LIST = (HTTPMethod.GET, CHANNELS + '/invites') CHANNELS_INVITES_LIST = (HTTPMethod.GET, CHANNELS + '/invites')
CHANNELS_INVITES_CREATE = (HTTPMethod.POST, CHANNELS + '/invites') CHANNELS_INVITES_CREATE = (HTTPMethod.POST, CHANNELS + '/invites')
CHANNELS_PINS_LIST = (HTTPMethod.GET, CHANNELS + '/pins') CHANNELS_PINS_LIST = (HTTPMethod.GET, CHANNELS + '/pins')
CHANNELS_PINS_CREATE = (HTTPMethod.PUT, CHANNELS + '/pins/{pin}') CHANNELS_PINS_CREATE = (HTTPMethod.PUT, CHANNELS + '/pins/{pin}')
CHANNELS_PINS_DELETE = (HTTPMethod.DELETE, CHANNELS + '/pins/{pin}') CHANNELS_PINS_DELETE = (HTTPMethod.DELETE, CHANNELS + '/pins/{pin}')
CHANNELS_WEBHOOKS_CREATE = (HTTPMethod.POST, CHANNELS + '/webhooks')
CHANNELS_WEBHOOKS_LIST = (HTTPMethod.GET, CHANNELS + '/webhooks')
# Guilds # Guilds
GUILDS = '/guilds/{guild}' GUILDS = '/guilds/{guild}'
@ -79,6 +78,7 @@ class Routes(object):
GUILDS_INTEGRATIONS_SYNC = (HTTPMethod.POST, GUILDS + '/integrations/{integration}/sync') GUILDS_INTEGRATIONS_SYNC = (HTTPMethod.POST, GUILDS + '/integrations/{integration}/sync')
GUILDS_EMBED_GET = (HTTPMethod.GET, GUILDS + '/embed') GUILDS_EMBED_GET = (HTTPMethod.GET, GUILDS + '/embed')
GUILDS_EMBED_MODIFY = (HTTPMethod.PATCH, GUILDS + '/embed') GUILDS_EMBED_MODIFY = (HTTPMethod.PATCH, GUILDS + '/embed')
GUILDS_WEBHOOKS_LIST = (HTTPMethod.GET, GUILDS + '/webhooks')
# Users # Users
USERS = '/users' USERS = '/users'
@ -96,6 +96,16 @@ class Routes(object):
INVITES_GET = (HTTPMethod.GET, INVITES + '/{invite}') INVITES_GET = (HTTPMethod.GET, INVITES + '/{invite}')
INVITES_DELETE = (HTTPMethod.DELETE, INVITES + '/{invite}') INVITES_DELETE = (HTTPMethod.DELETE, INVITES + '/{invite}')
# Webhooks
WEBHOOKS = '/webhooks/{webhook}'
WEBHOOKS_GET = (HTTPMethod.GET, WEBHOOKS)
WEBHOOKS_MODIFY = (HTTPMethod.PATCH, WEBHOOKS)
WEBHOOKS_DELETE = (HTTPMethod.DELETE, WEBHOOKS)
WEBHOOKS_TOKEN_GET = (HTTPMethod.GET, WEBHOOKS + '/{token}')
WEBHOOKS_TOKEN_MODIFY = (HTTPMethod.PATCH, WEBHOOKS + '/{token}')
WEBHOOKS_TOKEN_DELETE = (HTTPMethod.DELETE, WEBHOOKS + '/{token}')
WEBHOOKS_TOKEN_EXECUTE = (HTTPMethod.POST, WEBHOOKS + '/{token}')
class APIException(Exception): class APIException(Exception):
""" """
@ -201,7 +211,9 @@ class HTTPClient(LoggingClass):
raise APIException('Request failed after {} attempts'.format(self.MAX_RETRIES), r.status_code, r.content) raise APIException('Request failed after {} attempts'.format(self.MAX_RETRIES), r.status_code, r.content)
backoff = self.random_backoff() backoff = self.random_backoff()
self.log.warning('Request to `{}` failed with code {}, retrying after {}s'.format(url, r.status_code, backoff)) self.log.warning('Request to `{}` failed with code {}, retrying after {}s ({})'.format(
url, r.status_code, backoff, r.content
))
gevent.sleep(backoff) gevent.sleep(backoff)
# Otherwise just recurse and try again # Otherwise just recurse and try again

1
disco/gateway/events.py

@ -140,6 +140,7 @@ class GuildDelete(GatewayEvent):
unavailable = Field(bool) unavailable = Field(bool)
@debug()
@wraps_model(Channel) @wraps_model(Channel)
class ChannelCreate(GatewayEvent): class ChannelCreate(GatewayEvent):
""" """

2
disco/types/base.py

@ -104,7 +104,7 @@ def snowflake(data):
def enum(typ): def enum(typ):
def _f(data): def _f(data):
return typ.get(data) if data else None return typ.get(data) if data is not None else None
return _f return _f

6
disco/types/channel.py

@ -214,6 +214,12 @@ class Channel(SlottedModel, Permissible):
def delete_pin(self, message): def delete_pin(self, message):
self.client.api.channels_pins_delete(self.id, to_snowflake(message)) self.client.api.channels_pins_delete(self.id, to_snowflake(message))
def get_webhooks(self):
return self.client.api.channels_webhooks_list(self.id)
def create_webhook(self, name=None, avatar=None):
return self.client.api.channels_webhooks_create(self.id, name, avatar)
def send_message(self, content, nonce=None, tts=False): def send_message(self, content, nonce=None, tts=False):
""" """
Send a message in this channel Send a message in this channel

50
disco/types/message.py

@ -19,6 +19,45 @@ MessageType = Enum(
) )
class MessageEmbedFooter(SlottedModel):
text = Field(text)
icon_url = Field(text)
proxy_icon_url = Field(text)
class MessageEmbedImage(SlottedModel):
url = Field(text)
proxy_url = Field(text)
width = Field(int)
height = Field(int)
class MessageEmbedThumbnail(SlottedModel):
url = Field(text)
proxy_url = Field(text)
width = Field(int)
height = Field(int)
class MessageEmbedVideo(SlottedModel):
url = Field(text)
height = Field(int)
width = Field(int)
class MessageEmbedAuthor(SlottedModel):
name = Field(text)
url = Field(text)
icon_url = Field(text)
icon_proxy_url = Field(text)
class MessageEmbedField(SlottedModel):
name = Field(text)
value = Field(text)
inline = Field(bool)
class MessageEmbed(SlottedModel): class MessageEmbed(SlottedModel):
""" """
Message embed object Message embed object
@ -35,9 +74,17 @@ class MessageEmbed(SlottedModel):
URL of the embed. URL of the embed.
""" """
title = Field(text) title = Field(text)
type = Field(str) type = Field(str, default='rich')
description = Field(text) description = Field(text)
url = Field(str) url = Field(str)
timestamp = Field(lazy_datetime)
color = Field(int)
footer = Field(MessageEmbedFooter)
image = Field(MessageEmbedImage)
thumbnail = Field(MessageEmbedThumbnail)
video = Field(MessageEmbedVideo)
author = Field(MessageEmbedAuthor)
fields = Field(listof(MessageEmbedField))
class MessageAttachment(SlottedModel): class MessageAttachment(SlottedModel):
@ -109,6 +156,7 @@ class Message(SlottedModel):
""" """
id = Field(snowflake) id = Field(snowflake)
channel_id = Field(snowflake) channel_id = Field(snowflake)
webhook_id = Field(snowflake)
type = Field(enum(MessageType)) type = Field(enum(MessageType))
author = Field(User) author = Field(User)
content = Field(text) content = Field(text)

43
disco/types/webhook.py

@ -0,0 +1,43 @@
from disco.types.base import SlottedModel, Field, snowflake
from disco.types.user import User
from disco.util.functional import cached_property
class Webhook(SlottedModel):
id = Field(snowflake)
guild_id = Field(snowflake)
channel_id = Field(snowflake)
user = Field(User)
name = Field(str)
avatar = Field(str)
token = Field(str)
@cached_property
def guild(self):
return self.client.state.guilds.get(self.guild_id)
@cached_property
def channel(self):
return self.client.state.channels.get(self.channel_id)
def delete(self):
if self.token:
self.client.api.webhooks_token_delete(self.id, self.token)
else:
self.client.api.webhooks_delete(self.id)
def modify(self, name, avatar):
if self.token:
return self.client.api.webhooks_token_modify(self.id, self.token, name, avatar)
else:
return self.client.api.webhooks_modify(self.id, name, avatar)
def execute(self, content=None, username=None, avatar_url=None, tts=False, file=None, embeds=None, wait=False):
return self.client.api.webhooks_token_execute(self.id, self.token, {
'content': content,
'username': username,
'avatar_url': avatar_url,
'tts': tts,
'file': file,
'embeds': [i.to_dict() for i in embeds],
}, wait)
Loading…
Cancel
Save