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.channel import Channel
from disco.types.invite import Invite
from disco.types.webhook import Webhook
def optional(**kwargs):
@ -115,6 +116,17 @@ class APIClient(LoggingClass):
def channels_pins_delete(self, channel, 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):
r = self.http(Routes.GUILDS_GET, dict(guild=guild))
return Guild.create(self.client, r.json())
@ -186,6 +198,10 @@ class APIClient(LoggingClass):
def guilds_roles_delete(self, guild, 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):
r = self.http(Routes.INVITES_GET, dict(invite=invite))
return Invite.create(self.client, r.json())
@ -193,3 +209,37 @@ class APIClient(LoggingClass):
def invites_delete(self, invite):
r = self.http(Routes.INVITES_DELETE, dict(invite=invite))
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_MODIFY = (HTTPMethod.PATCH, CHANNELS)
CHANNELS_DELETE = (HTTPMethod.DELETE, CHANNELS)
CHANNELS_MESSAGES_LIST = (HTTPMethod.GET, CHANNELS + '/messages')
CHANNELS_MESSAGES_GET = (HTTPMethod.GET, CHANNELS + '/messages/{message}')
CHANNELS_MESSAGES_CREATE = (HTTPMethod.POST, CHANNELS + '/messages')
CHANNELS_MESSAGES_MODIFY = (HTTPMethod.PATCH, CHANNELS + '/messages/{message}')
CHANNELS_MESSAGES_DELETE = (HTTPMethod.DELETE, CHANNELS + '/messages/{message}')
CHANNELS_MESSAGES_DELETE_BULK = (HTTPMethod.POST, CHANNELS + '/messages/bulk_delete')
CHANNELS_PERMISSIONS_MODIFY = (HTTPMethod.PUT, CHANNELS + '/permissions/{permission}')
CHANNELS_PERMISSIONS_DELETE = (HTTPMethod.DELETE, CHANNELS + '/permissions/{permission}')
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/{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/{guild}'
@ -79,6 +78,7 @@ class Routes(object):
GUILDS_INTEGRATIONS_SYNC = (HTTPMethod.POST, GUILDS + '/integrations/{integration}/sync')
GUILDS_EMBED_GET = (HTTPMethod.GET, GUILDS + '/embed')
GUILDS_EMBED_MODIFY = (HTTPMethod.PATCH, GUILDS + '/embed')
GUILDS_WEBHOOKS_LIST = (HTTPMethod.GET, GUILDS + '/webhooks')
# Users
USERS = '/users'
@ -96,6 +96,16 @@ class Routes(object):
INVITES_GET = (HTTPMethod.GET, 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):
"""
@ -201,7 +211,9 @@ class HTTPClient(LoggingClass):
raise APIException('Request failed after {} attempts'.format(self.MAX_RETRIES), r.status_code, r.content)
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)
# Otherwise just recurse and try again

1
disco/gateway/events.py

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

2
disco/types/base.py

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

6
disco/types/channel.py

@ -214,6 +214,12 @@ class Channel(SlottedModel, Permissible):
def delete_pin(self, 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):
"""
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):
"""
Message embed object
@ -35,9 +74,17 @@ class MessageEmbed(SlottedModel):
URL of the embed.
"""
title = Field(text)
type = Field(str)
type = Field(str, default='rich')
description = Field(text)
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):
@ -109,6 +156,7 @@ class Message(SlottedModel):
"""
id = Field(snowflake)
channel_id = Field(snowflake)
webhook_id = Field(snowflake)
type = Field(enum(MessageType))
author = Field(User)
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