Add support for integrations
This commit is contained in:
		| @@ -39,6 +39,7 @@ from .permissions import Permissions, PermissionOverwrite | |||||||
| from .role import Role | from .role import Role | ||||||
| from .file import File | from .file import File | ||||||
| from .colour import Color, Colour | from .colour import Color, Colour | ||||||
|  | from .integrations import Integration, IntegrationAccount | ||||||
| from .invite import Invite, PartialInviteChannel, PartialInviteGuild | from .invite import Invite, PartialInviteChannel, PartialInviteGuild | ||||||
| from .template import Template | from .template import Template | ||||||
| from .widget import Widget, WidgetMember, WidgetChannel | from .widget import Widget, WidgetMember, WidgetChannel | ||||||
|   | |||||||
| @@ -50,6 +50,8 @@ __all__ = ( | |||||||
|     'TeamMembershipState', |     'TeamMembershipState', | ||||||
|     'Theme', |     'Theme', | ||||||
|     'WebhookType', |     'WebhookType', | ||||||
|  |     'ExpireBehaviour', | ||||||
|  |     'ExpireBehavior' | ||||||
| ) | ) | ||||||
|  |  | ||||||
| def _create_value_cls(name): | def _create_value_cls(name): | ||||||
| @@ -432,6 +434,12 @@ class WebhookType(Enum): | |||||||
|     incoming = 1 |     incoming = 1 | ||||||
|     channel_follower = 2 |     channel_follower = 2 | ||||||
|  |  | ||||||
|  | class ExpireBehaviour(Enum): | ||||||
|  |     remove_role = 0 | ||||||
|  |     kick = 1 | ||||||
|  |  | ||||||
|  | ExpireBehavior = ExpireBehaviour | ||||||
|  |  | ||||||
| def try_enum(cls, val): | def try_enum(cls, val): | ||||||
|     """A function that tries to turn the value into enum ``cls``. |     """A function that tries to turn the value into enum ``cls``. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -46,6 +46,8 @@ from .webhook import Webhook | |||||||
| from .widget import Widget | from .widget import Widget | ||||||
| from .asset import Asset | from .asset import Asset | ||||||
| from .flags import SystemChannelFlags | from .flags import SystemChannelFlags | ||||||
|  | from .integrations import Integration | ||||||
|  |  | ||||||
|  |  | ||||||
| BanEntry = namedtuple('BanEntry', 'reason user') | BanEntry = namedtuple('BanEntry', 'reason user') | ||||||
| _GuildLimit = namedtuple('_GuildLimit', 'emoji bitrate filesize') | _GuildLimit = namedtuple('_GuildLimit', 'emoji bitrate filesize') | ||||||
| @@ -1535,6 +1537,100 @@ class Guild(Hashable): | |||||||
|         data = await self._state.http.get_custom_emoji(self.id, emoji_id) |         data = await self._state.http.get_custom_emoji(self.id, emoji_id) | ||||||
|         return Emoji(guild=self, state=self._state, data=data) |         return Emoji(guild=self, state=self._state, data=data) | ||||||
|  |  | ||||||
|  |     async def create_integration(self, *, type, id): | ||||||
|  |         """|coro| | ||||||
|  |  | ||||||
|  |         Attaches an integration to the guild. | ||||||
|  |  | ||||||
|  |         You must have the :attr:`~Permissions.manage_guild` permission to | ||||||
|  |         do this. | ||||||
|  |  | ||||||
|  |         .. versionadded:: 1.4 | ||||||
|  |  | ||||||
|  |         Parameters | ||||||
|  |         ----------- | ||||||
|  |         type: :class:`str` | ||||||
|  |             The integration type (e.g. Twitch). | ||||||
|  |         id: :class:`int` | ||||||
|  |             The integration ID. | ||||||
|  |  | ||||||
|  |         Raises | ||||||
|  |         ------- | ||||||
|  |         Forbidden | ||||||
|  |             You do not have permission to create the integration. | ||||||
|  |         HTTPException | ||||||
|  |             The account could not be found. | ||||||
|  |         """ | ||||||
|  |         await self._state.http.create_integration(self.id, type, id) | ||||||
|  |  | ||||||
|  |     async def integrations(self): | ||||||
|  |         """|coro| | ||||||
|  |  | ||||||
|  |         Returns a list of all integrations attached to the guild. | ||||||
|  |  | ||||||
|  |         You must have the :attr:`~Permissions.manage_guild` permission to | ||||||
|  |         do this. | ||||||
|  |  | ||||||
|  |         .. versionadded:: 1.4 | ||||||
|  |  | ||||||
|  |         Raises | ||||||
|  |         ------- | ||||||
|  |         Forbidden | ||||||
|  |             You do not have permission to create the integration. | ||||||
|  |         HTTPException | ||||||
|  |             Fetching the integrations failed. | ||||||
|  |  | ||||||
|  |         Returns | ||||||
|  |         -------- | ||||||
|  |         List[:class:`Integration`] | ||||||
|  |             The list of integrations that are attached to the guild. | ||||||
|  |         """ | ||||||
|  |         data = await self._state.http.get_all_integrations(self.id) | ||||||
|  |         return [Integration(guild=self, data=d) for d in data] | ||||||
|  |  | ||||||
|  |     async def fetch_emojis(self): | ||||||
|  |         """|coro| | ||||||
|  |  | ||||||
|  |         Retrieves all custom :class:`Emoji`s from the guild. | ||||||
|  |  | ||||||
|  |         Raises | ||||||
|  |         --------- | ||||||
|  |         HTTPException | ||||||
|  |             An error occurred fetching the emojis. | ||||||
|  |  | ||||||
|  |         Returns | ||||||
|  |         -------- | ||||||
|  |         List[:class:`Emoji`] | ||||||
|  |             The retrieved emojis. | ||||||
|  |         """ | ||||||
|  |         data = await self._state.http.get_all_custom_emojis(self.id) | ||||||
|  |         return [Emoji(guild=self, state=self._state, data=d) for d in data] | ||||||
|  |  | ||||||
|  |     async def fetch_emoji(self, emoji_id): | ||||||
|  |         """|coro| | ||||||
|  |  | ||||||
|  |         Retrieves a custom :class:`Emoji` from the guild. | ||||||
|  |  | ||||||
|  |         Parameters | ||||||
|  |         ------------- | ||||||
|  |         emoji_id: :class:`int` | ||||||
|  |             The emoji's ID. | ||||||
|  |  | ||||||
|  |         Raises | ||||||
|  |         --------- | ||||||
|  |         NotFound | ||||||
|  |             The emoji requested could not be found. | ||||||
|  |         HTTPException | ||||||
|  |             An error occurred fetching the emoji. | ||||||
|  |  | ||||||
|  |         Returns | ||||||
|  |         -------- | ||||||
|  |         :class:`Emoji` | ||||||
|  |             The retrieved emoji. | ||||||
|  |         """ | ||||||
|  |         data = await self._state.http.get_custom_emoji(self.id, emoji_id) | ||||||
|  |         return Emoji(guild=self, state=self._state, data=data) | ||||||
|  |  | ||||||
|     async def create_custom_emoji(self, *, name, image, roles=None, reason=None): |     async def create_custom_emoji(self, *, name, image, roles=None, reason=None): | ||||||
|         r"""|coro| |         r"""|coro| | ||||||
|  |  | ||||||
|   | |||||||
| @@ -712,6 +712,38 @@ class HTTPClient: | |||||||
|         r = Route('PATCH', '/guilds/{guild_id}/emojis/{emoji_id}', guild_id=guild_id, emoji_id=emoji_id) |         r = Route('PATCH', '/guilds/{guild_id}/emojis/{emoji_id}', guild_id=guild_id, emoji_id=emoji_id) | ||||||
|         return self.request(r, json=payload, reason=reason) |         return self.request(r, json=payload, reason=reason) | ||||||
|  |  | ||||||
|  |     def get_all_integrations(self, guild_id): | ||||||
|  |         r = Route('GET', '/guilds/{guild_id}/integrations', guild_id=guild_id) | ||||||
|  |  | ||||||
|  |         return self.request(r) | ||||||
|  |  | ||||||
|  |     def create_integration(self, guild_id, type, id): | ||||||
|  |         payload = { | ||||||
|  |             'type': type, | ||||||
|  |             'id': id | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         r = Route('POST', '/guilds/{guild_id}/integrations', guild_id=guild_id) | ||||||
|  |         return self.request(r, json=payload) | ||||||
|  |  | ||||||
|  |     def edit_integration(self, guild_id, integration_id, **payload): | ||||||
|  |         r = Route('PATCH', '/guilds/{guild_id}/integrations/{integration_id}', guild_id=guild_id, | ||||||
|  |                   integration_id=integration_id) | ||||||
|  |  | ||||||
|  |         return self.request(r, json=payload) | ||||||
|  |  | ||||||
|  |     def sync_integration(self, guild_id, integration_id): | ||||||
|  |         r = Route('POST', '/guilds/{guild_id}/integrations/{integration_id}/sync', guild_id=guild_id, | ||||||
|  |                   integration_id=integration_id) | ||||||
|  |  | ||||||
|  |         return self.request(r) | ||||||
|  |  | ||||||
|  |     def delete_integration(self, guild_id, integration_id): | ||||||
|  |         r = Route('DELETE', '/guilds/{guild_id}/integrations/{integration_id}', guild_id=guild_id, | ||||||
|  |                   integration_id=integration_id) | ||||||
|  |  | ||||||
|  |         return self.request(r) | ||||||
|  |  | ||||||
|     def get_audit_logs(self, guild_id, limit=100, before=None, after=None, user_id=None, action_type=None): |     def get_audit_logs(self, guild_id, limit=100, before=None, after=None, user_id=None, action_type=None): | ||||||
|         params = {'limit': limit} |         params = {'limit': limit} | ||||||
|         if before: |         if before: | ||||||
|   | |||||||
							
								
								
									
										202
									
								
								discord/integrations.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								discord/integrations.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | |||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  |  | ||||||
|  | """ | ||||||
|  | The MIT License (MIT) | ||||||
|  |  | ||||||
|  | Copyright (c) 2015-2020 Rapptz | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a | ||||||
|  | copy of this software and associated documentation files (the "Software"), | ||||||
|  | to deal in the Software without restriction, including without limitation | ||||||
|  | the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||||
|  | and/or sell copies of the Software, and to permit persons to whom the | ||||||
|  | Software is furnished to do so, subject to the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be included in | ||||||
|  | all copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||||
|  | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||||
|  | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||||
|  | DEALINGS IN THE SOFTWARE. | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | import datetime | ||||||
|  | from collections import namedtuple | ||||||
|  | from .utils import _get_as_snowflake, get, parse_time | ||||||
|  | from .user import User | ||||||
|  | from .errors import InvalidArgument | ||||||
|  | from .enums import try_enum, ExpireBehaviour | ||||||
|  |  | ||||||
|  | class IntegrationAccount(namedtuple('IntegrationAccount', 'id name')): | ||||||
|  |     """Represents an integration account. | ||||||
|  |  | ||||||
|  |     .. versionadded:: 1.4 | ||||||
|  |  | ||||||
|  |     Attributes | ||||||
|  |     ----------- | ||||||
|  |     id: :class:`int` | ||||||
|  |         The account ID. | ||||||
|  |     name: :class:`str` | ||||||
|  |         The account name. | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     __slots__ = () | ||||||
|  |  | ||||||
|  |     def __repr__(self): | ||||||
|  |         return '<IntegrationAccount id={0.id} name={0.name!r}>'.format(self) | ||||||
|  |  | ||||||
|  | class Integration: | ||||||
|  |     """Represents a guild integration. | ||||||
|  |  | ||||||
|  |     .. versionadded:: 1.4 | ||||||
|  |  | ||||||
|  |     Attributes | ||||||
|  |     ----------- | ||||||
|  |     id: :class:`int` | ||||||
|  |         The integration ID. | ||||||
|  |     name: :class:`str` | ||||||
|  |         The integration name. | ||||||
|  |     guild: :class:`Guild` | ||||||
|  |         The guild of the integration. | ||||||
|  |     type: :class:`str` | ||||||
|  |         The integration type (i.e. Twitch). | ||||||
|  |     enabled: :class:`bool` | ||||||
|  |         Whether the integration is currently enabled. | ||||||
|  |     syncing: :class:`bool` | ||||||
|  |         Where the integration is currently syncing. | ||||||
|  |     role: :class:`Role` | ||||||
|  |         The role which the integration uses for subscribers. | ||||||
|  |     enable_emoticons: :class:`bool` | ||||||
|  |         Whether emoticons should be synced for this integration (currently twitch only). | ||||||
|  |     expire_behaviour: :class:`ExpireBehaviour` | ||||||
|  |         The behaviour of expiring subscribers. Aliased to ``expire_behavior`` as well. | ||||||
|  |     expire_grace_period: :class:`int` | ||||||
|  |         The grace period (in days) for expiring subscribers. | ||||||
|  |     user: :class:`User` | ||||||
|  |         The user for the integration. | ||||||
|  |     account: :class:`IntegrationAccount` | ||||||
|  |         The integration account information. | ||||||
|  |     synced_at: :class:`datetime.datetime` | ||||||
|  |         When the integration was last synced. | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     __slots__ = ('id', '_state', 'guild', 'name', 'enabled', 'type', | ||||||
|  |                  'syncing', 'role', 'expire_behaviour', 'expire_behavior', | ||||||
|  |                  'expire_grace_period', 'synced_at', 'user', 'account') | ||||||
|  |  | ||||||
|  |     def __init__(self, *, data, guild): | ||||||
|  |         self.guild = guild | ||||||
|  |         self._state = guild._state | ||||||
|  |         self._from_data(data) | ||||||
|  |  | ||||||
|  |     def __repr__(self): | ||||||
|  |         return '<Integration id={0.id} name={0.name!r} type={0.type!r}>'.format(self) | ||||||
|  |  | ||||||
|  |     def _from_data(self, integ): | ||||||
|  |         self.id = _get_as_snowflake(integ, 'id') | ||||||
|  |         self.name = integ['name'] | ||||||
|  |         self.type = integ['type'] | ||||||
|  |         self.enabled = integ['enabled'] | ||||||
|  |         self.syncing = integ['syncing'] | ||||||
|  |         self._role_id = _get_as_snowflake(integ, 'role_id') | ||||||
|  |         self.role = get(self.guild.roles, id=self._role_id) | ||||||
|  |         self.enable_emoticons = integ.get('enable_emoticons') | ||||||
|  |         self.expire_behaviour = try_enum(ExpireBehaviour, integ['expire_behavior']) | ||||||
|  |         self.expire_behavior = self.expire_behaviour | ||||||
|  |         self.expire_grace_period = integ['expire_grace_period'] | ||||||
|  |         self.synced_at = parse_time(integ['synced_at']) | ||||||
|  |  | ||||||
|  |         self.user = User(state=self._state, data=integ['user']) | ||||||
|  |         self.account = IntegrationAccount(**integ['account']) | ||||||
|  |  | ||||||
|  |     async def edit(self, **fields): | ||||||
|  |         """|coro| | ||||||
|  |  | ||||||
|  |         Edits the integration. | ||||||
|  |  | ||||||
|  |         You must have the :attr:`~Permissions.manage_guild` permission to | ||||||
|  |         do this. | ||||||
|  |  | ||||||
|  |         Parameters | ||||||
|  |         ----------- | ||||||
|  |         expire_behaviour: :class:`ExpireBehaviour` | ||||||
|  |             The behaviour when an integration subscription lapses. Aliased to ``expire_behavior`` as well. | ||||||
|  |         expire_grace_period: :class:`int` | ||||||
|  |             The period (in days) where the integration will ignore lapsed subscriptions. | ||||||
|  |         enable_emoticons: :class:`bool` | ||||||
|  |             Where emoticons should be synced for this integration (currently twitch only). | ||||||
|  |  | ||||||
|  |         Raises | ||||||
|  |         ------- | ||||||
|  |         Forbidden | ||||||
|  |             You do not have permission to edit the integration. | ||||||
|  |         HTTPException | ||||||
|  |             Editing the guild failed. | ||||||
|  |         InvalidArgument | ||||||
|  |             ``expire_behaviour`` did not receive a :class:`ExpireBehaviour`. | ||||||
|  |         """ | ||||||
|  |         try: | ||||||
|  |             expire_behaviour = fields['expire_behaviour'] | ||||||
|  |         except KeyError: | ||||||
|  |             expire_behaviour = fields.get('expire_behavior', self.expire_behaviour) | ||||||
|  |  | ||||||
|  |         if not isinstance(expire_behaviour, ExpireBehaviour): | ||||||
|  |             raise InvalidArgument('expire_behaviour field must be of type ExpireBehaviour') | ||||||
|  |  | ||||||
|  |         expire_grace_period = fields.get('expire_grace_period', self.expire_grace_period) | ||||||
|  |  | ||||||
|  |         payload = { | ||||||
|  |             'expire_behavior': expire_behaviour.value, | ||||||
|  |             'expire_grace_period': expire_grace_period, | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         enable_emoticons = fields.get('enable_emoticons') | ||||||
|  |  | ||||||
|  |         if enable_emoticons is not None: | ||||||
|  |             payload['enable_emoticons'] = enable_emoticons | ||||||
|  |  | ||||||
|  |         await self._state.http.edit_integration(self.guild.id, self.id, **payload) | ||||||
|  |  | ||||||
|  |         self.expire_behaviour = expire_behavior | ||||||
|  |         self.expire_behavior = self.expire_behaviour | ||||||
|  |         self.expire_grace_period = expire_grace_period | ||||||
|  |         self.enable_emoticons = enable_emoticons | ||||||
|  |  | ||||||
|  |     async def sync(self): | ||||||
|  |         """|coro| | ||||||
|  |  | ||||||
|  |         Syncs the integration. | ||||||
|  |  | ||||||
|  |         You must have the :attr:`~Permissions.manage_guild` permission to | ||||||
|  |         do this. | ||||||
|  |  | ||||||
|  |         Raises | ||||||
|  |         ------- | ||||||
|  |         Forbidden | ||||||
|  |             You do not have permission to sync the integration. | ||||||
|  |         HTTPException | ||||||
|  |             Syncing the integration failed. | ||||||
|  |         """ | ||||||
|  |         await self._state.http.sync_integration(self.guild.id, self.id) | ||||||
|  |         self.synced_at = datetime.datetime.utcnow() | ||||||
|  |  | ||||||
|  |     async def delete(self): | ||||||
|  |         """|coro| | ||||||
|  |  | ||||||
|  |         Deletes the integration. | ||||||
|  |  | ||||||
|  |         You must have the :attr:`~Permissions.manage_guild` permission to | ||||||
|  |         do this. | ||||||
|  |  | ||||||
|  |         Raises | ||||||
|  |         ------- | ||||||
|  |         Forbidden | ||||||
|  |             You do not have permission to delete the integration. | ||||||
|  |         HTTPException | ||||||
|  |             Deleting the integration failed. | ||||||
|  |         """ | ||||||
|  |         await self._state.http.delete_integration(self.guild.id, self.id) | ||||||
							
								
								
									
										31
									
								
								docs/api.rst
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								docs/api.rst
									
									
									
									
									
								
							| @@ -480,6 +480,8 @@ to handle it, which defaults to print a traceback and ignoring the exception. | |||||||
|  |  | ||||||
| .. function:: on_guild_integrations_update(guild) | .. function:: on_guild_integrations_update(guild) | ||||||
|  |  | ||||||
|  |     .. versionadded:: 1.4 | ||||||
|  |  | ||||||
|     Called whenever an integration is created, modified, or removed from a guild. |     Called whenever an integration is created, modified, or removed from a guild. | ||||||
|  |  | ||||||
|     :param guild: The guild that had its integrations updated. |     :param guild: The guild that had its integrations updated. | ||||||
| @@ -1670,7 +1672,6 @@ of :class:`enum.Enum`. | |||||||
|  |  | ||||||
|         The action is the update of something. |         The action is the update of something. | ||||||
|  |  | ||||||
|  |  | ||||||
| .. class:: RelationshipType | .. class:: RelationshipType | ||||||
|  |  | ||||||
|     Specifies the type of :class:`Relationship`. |     Specifies the type of :class:`Relationship`. | ||||||
| @@ -1810,6 +1811,24 @@ of :class:`enum.Enum`. | |||||||
|  |  | ||||||
|         Represents a webhook that is internally managed by Discord, used for following channels. |         Represents a webhook that is internally managed by Discord, used for following channels. | ||||||
|  |  | ||||||
|  | .. class:: ExpireBehaviour | ||||||
|  |  | ||||||
|  |     Represents the behaviour the :class:`Integration` should perform | ||||||
|  |     when a user's subscription has finished. | ||||||
|  |  | ||||||
|  |     There is an alias for this called ``ExpireBehavior``. | ||||||
|  |  | ||||||
|  |     .. versionadded:: 1.4 | ||||||
|  |  | ||||||
|  |     .. attribute:: remove_role | ||||||
|  |  | ||||||
|  |         This will remove the :attr:`Integration.role` from the user | ||||||
|  |         when their subscription is finished. | ||||||
|  |  | ||||||
|  |     .. attribute:: kick | ||||||
|  |  | ||||||
|  |         This will kick the user when their subscription is finished. | ||||||
|  |  | ||||||
| .. class:: DefaultAvatar | .. class:: DefaultAvatar | ||||||
|  |  | ||||||
|     Represents the default avatar of a Discord :class:`User` |     Represents the default avatar of a Discord :class:`User` | ||||||
| @@ -1838,6 +1857,7 @@ of :class:`enum.Enum`. | |||||||
|         Represents the default avatar with the color red. |         Represents the default avatar with the color red. | ||||||
|         See also :attr:`Colour.red` |         See also :attr:`Colour.red` | ||||||
|  |  | ||||||
|  |  | ||||||
| Async Iterator | Async Iterator | ||||||
| ---------------- | ---------------- | ||||||
|  |  | ||||||
| @@ -2507,6 +2527,15 @@ Guild | |||||||
|     .. automethod:: audit_logs |     .. automethod:: audit_logs | ||||||
|         :async-for: |         :async-for: | ||||||
|  |  | ||||||
|  | Integration | ||||||
|  | ~~~~~~~~~~~~ | ||||||
|  |  | ||||||
|  | .. autoclass:: Integration() | ||||||
|  |     :members: | ||||||
|  |  | ||||||
|  | .. autoclass:: IntegrationAccount() | ||||||
|  |     :members: | ||||||
|  |  | ||||||
| Member | Member | ||||||
| ~~~~~~ | ~~~~~~ | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user