diff --git a/discord/channel.py b/discord/channel.py index de9381421..f066e6209 100644 --- a/discord/channel.py +++ b/discord/channel.py @@ -33,7 +33,7 @@ from .enums import ChannelType, try_enum from .mixins import Hashable from . import utils from .asset import Asset -from .errors import ClientException, NoMoreItems +from .errors import ClientException, NoMoreItems, InvalidArgument from .webhook import Webhook __all__ = ( @@ -455,6 +455,46 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): data = await self._state.http.create_webhook(self.id, name=str(name), avatar=avatar, reason=reason) return Webhook.from_state(data, state=self._state) + async def follow(self, *, destination): + """ + Follows a channel using a webhook. + + Only news channels can be followed. + + .. note:: + + The webhook returned will not provide a token to do webhook + actions, as Discord does not provide it. + + .. versionadded:: 1.3.0 + + Parameters + ----------- + destination: :class:`TextChannel` + The channel you would like to follow from. + + Raises + ------- + HTTPException + Following the channel failed. + Forbidden + You do not have the permissions to create a webhook. + + Returns + -------- + :class:`Webhook` + The created webhook. + """ + + if not self.is_news(): + raise ClientException('The channel must be a news channel.') + + if not isinstance(destination, TextChannel): + raise InvalidArgument('Expected TextChannel received {0.__name__}'.format(type(destination))) + + data = await self._state.http.follow_webhook(self.id, webhook_channel_id=destination.id) + return Webhook._as_follower(data, channel=destination, user=self._state.user) + class VoiceChannel(discord.abc.Connectable, discord.abc.GuildChannel, Hashable): """Represents a Discord guild voice channel. diff --git a/discord/http.py b/discord/http.py index 70a04bda0..ed06996c9 100644 --- a/discord/http.py +++ b/discord/http.py @@ -564,6 +564,12 @@ class HTTPClient: def get_webhook(self, webhook_id): return self.request(Route('GET', '/webhooks/{webhook_id}', webhook_id=webhook_id)) + def follow_webhook(self, channel_id, webhook_channel_id): + payload = { + 'webhook_channel_id': str(webhook_channel_id) + } + return self.request(Route('POST', '/channels/{channel_id}/followers', channel_id=channel_id), json=payload) + # Guild management def get_guilds(self, limit, before=None, after=None): diff --git a/discord/webhook.py b/discord/webhook.py index 00e154292..f717108a6 100644 --- a/discord/webhook.py +++ b/discord/webhook.py @@ -499,6 +499,25 @@ class Webhook: raise InvalidArgument('Invalid webhook URL given.') return cls(m.groupdict(), adapter=adapter) + @classmethod + def _as_follower(cls, data, *, channel, user): + name = "{} #{}".format(channel.guild, channel) + feed = { + 'id': data['webhook_id'], + 'name': name, + 'channel_id': channel.id, + 'guild_id': channel.guild.id, + 'user': { + 'username': user.name, + 'discriminator': user.discriminator, + 'id': user.id, + 'avatar': user.avatar + } + } + + session = channel._state.http._HTTPClient__session + return cls(feed, adapter=AsyncWebhookAdapter(session=session)) + @classmethod def from_state(cls, data, state): session = state.http._HTTPClient__session