mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-06-05 11:27:13 +00:00
Add support for Discord templates
This commit is contained in:
parent
7a07644de3
commit
2b3c6e0d47
@ -40,6 +40,7 @@ from .role import Role
|
|||||||
from .file import File
|
from .file import File
|
||||||
from .colour import Color, Colour
|
from .colour import Color, Colour
|
||||||
from .invite import Invite, PartialInviteChannel, PartialInviteGuild
|
from .invite import Invite, PartialInviteChannel, PartialInviteGuild
|
||||||
|
from .template import Template
|
||||||
from .widget import Widget, WidgetMember, WidgetChannel
|
from .widget import Widget, WidgetMember, WidgetChannel
|
||||||
from .object import Object
|
from .object import Object
|
||||||
from .reaction import Reaction
|
from .reaction import Reaction
|
||||||
|
@ -37,6 +37,7 @@ import websockets
|
|||||||
from .user import User, Profile
|
from .user import User, Profile
|
||||||
from .asset import Asset
|
from .asset import Asset
|
||||||
from .invite import Invite
|
from .invite import Invite
|
||||||
|
from .template import Template
|
||||||
from .widget import Widget
|
from .widget import Widget
|
||||||
from .guild import Guild
|
from .guild import Guild
|
||||||
from .channel import _channel_factory
|
from .channel import _channel_factory
|
||||||
@ -1019,6 +1020,32 @@ class Client:
|
|||||||
"""
|
"""
|
||||||
return GuildIterator(self, limit=limit, before=before, after=after)
|
return GuildIterator(self, limit=limit, before=before, after=after)
|
||||||
|
|
||||||
|
async def fetch_template(self, code):
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Gets a :class:`.Template` from a discord.new URL or code.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
code: :class:`str`
|
||||||
|
The Discord Template Code or URL (must be a discord.new URL).
|
||||||
|
|
||||||
|
Raises
|
||||||
|
-------
|
||||||
|
:exc:`.NotFound`
|
||||||
|
The template is invalid.
|
||||||
|
:exc:`.HTTPException`
|
||||||
|
Getting the template failed.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
:class:`.Template`
|
||||||
|
The template from the URL/code.
|
||||||
|
"""
|
||||||
|
code = utils.resolve_template(code)
|
||||||
|
data = await self.http.get_template(code)
|
||||||
|
return Template(data=data, state=self._connection)
|
||||||
|
|
||||||
async def fetch_guild(self, guild_id):
|
async def fetch_guild(self, guild_id):
|
||||||
"""|coro|
|
"""|coro|
|
||||||
|
|
||||||
@ -1053,7 +1080,7 @@ class Client:
|
|||||||
data = await self.http.get_guild(guild_id)
|
data = await self.http.get_guild(guild_id)
|
||||||
return Guild(data=data, state=self._connection)
|
return Guild(data=data, state=self._connection)
|
||||||
|
|
||||||
async def create_guild(self, name, region=None, icon=None):
|
async def create_guild(self, name, region=None, icon=None, *, code=None):
|
||||||
"""|coro|
|
"""|coro|
|
||||||
|
|
||||||
Creates a :class:`.Guild`.
|
Creates a :class:`.Guild`.
|
||||||
@ -1070,6 +1097,10 @@ class Client:
|
|||||||
icon: :class:`bytes`
|
icon: :class:`bytes`
|
||||||
The :term:`py:bytes-like object` representing the icon. See :meth:`.ClientUser.edit`
|
The :term:`py:bytes-like object` representing the icon. See :meth:`.ClientUser.edit`
|
||||||
for more details on what is expected.
|
for more details on what is expected.
|
||||||
|
code: Optional[:class:`str`]
|
||||||
|
The code for a template to create the guild with.
|
||||||
|
|
||||||
|
.. versionadded:: 1.4
|
||||||
|
|
||||||
Raises
|
Raises
|
||||||
------
|
------
|
||||||
@ -1092,7 +1123,10 @@ class Client:
|
|||||||
else:
|
else:
|
||||||
region = region.value
|
region = region.value
|
||||||
|
|
||||||
data = await self.http.create_guild(name, region, icon)
|
if code:
|
||||||
|
data = await self.http.create_from_template(code, name, region, icon)
|
||||||
|
else:
|
||||||
|
data = await self.http.create_guild(name, region, icon)
|
||||||
return Guild(data=data, state=self._connection)
|
return Guild(data=data, state=self._connection)
|
||||||
|
|
||||||
# Invite management
|
# Invite management
|
||||||
|
@ -630,6 +630,17 @@ class HTTPClient:
|
|||||||
|
|
||||||
return self.request(Route('PATCH', '/guilds/{guild_id}', guild_id=guild_id), json=payload, reason=reason)
|
return self.request(Route('PATCH', '/guilds/{guild_id}', guild_id=guild_id), json=payload, reason=reason)
|
||||||
|
|
||||||
|
def get_template(self, code):
|
||||||
|
return self.request(Route('GET', '/guilds/templates/{code}', code=code))
|
||||||
|
|
||||||
|
def create_from_template(self, code, name, region, icon):
|
||||||
|
payload = {
|
||||||
|
'name': name,
|
||||||
|
'icon': icon,
|
||||||
|
'region': region
|
||||||
|
}
|
||||||
|
return self.request(Route('POST', '/guilds/templates/{code}', code=code), json=payload)
|
||||||
|
|
||||||
def get_bans(self, guild_id):
|
def get_bans(self, guild_id):
|
||||||
return self.request(Route('GET', '/guilds/{guild_id}/bans', guild_id=guild_id))
|
return self.request(Route('GET', '/guilds/{guild_id}/bans', guild_id=guild_id))
|
||||||
|
|
||||||
|
140
discord/template.py
Normal file
140
discord/template.py
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
from .utils import parse_time, _get_as_snowflake
|
||||||
|
from .enums import VoiceRegion
|
||||||
|
from .guild import Guild
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
'Template'
|
||||||
|
)
|
||||||
|
|
||||||
|
class _FriendlyHttpAttributeErrorHelper:
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
raise AttributeError('PartialTemplateState does not support http methods.')
|
||||||
|
|
||||||
|
class _PartialTemplateState:
|
||||||
|
def __init__(self, *, state):
|
||||||
|
self.__state = state
|
||||||
|
self.http = _FriendlyHttpAttributeErrorHelper()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_bot(self):
|
||||||
|
return self.__state.is_bot
|
||||||
|
|
||||||
|
@property
|
||||||
|
def shard_count(self):
|
||||||
|
return self.__state.shard_count
|
||||||
|
|
||||||
|
@property
|
||||||
|
def user(self):
|
||||||
|
return self.__state.user
|
||||||
|
|
||||||
|
@property
|
||||||
|
def self_id(self):
|
||||||
|
return self.__state.user.id
|
||||||
|
|
||||||
|
def store_emoji(self, guild, packet):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _get_voice_client(self, id):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _get_message(self, id):
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def query_members(self, **kwargs):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
raise AttributeError('PartialTemplateState does not support {0!r}.'.format(attr))
|
||||||
|
|
||||||
|
class Template:
|
||||||
|
"""Represents a Discord template.
|
||||||
|
|
||||||
|
.. versionadded:: 1.4
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
-----------
|
||||||
|
code: :code:`str`
|
||||||
|
The template code.
|
||||||
|
uses: :class:`int`
|
||||||
|
How many time the template has been used.
|
||||||
|
name: :class:`str`
|
||||||
|
The name of the template.
|
||||||
|
description: :class:`str`
|
||||||
|
The description of the template.
|
||||||
|
creator: :class:`User`
|
||||||
|
The creator of the template.
|
||||||
|
created_at: :class:`datetime.datetime`
|
||||||
|
When the template was created.
|
||||||
|
updated_at: :class:`datetime.datetime`
|
||||||
|
When the template was last updated (referred to as "last synced" in the client).
|
||||||
|
source_guild: :class:`TemplateGuild`
|
||||||
|
The source guild.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *, state, data):
|
||||||
|
self._state = state
|
||||||
|
|
||||||
|
self.code = data['code']
|
||||||
|
self.uses = data['usage_count']
|
||||||
|
self.name = data['name']
|
||||||
|
self.description = data['description']
|
||||||
|
creator_data = data.get('creator')
|
||||||
|
self.creator = None if creator_data is None else self._state.store_user(creator_data)
|
||||||
|
|
||||||
|
self.created_at = parse_time(data.get('created_at'))
|
||||||
|
self.updated_at = parse_time(data.get('updated_at'))
|
||||||
|
|
||||||
|
id = _get_as_snowflake(data, 'source_guild_id')
|
||||||
|
source_serialised = data['serialized_source_guild']
|
||||||
|
source_serialised['id'] = id
|
||||||
|
state = _PartialTemplateState(state=self._state)
|
||||||
|
|
||||||
|
self.source_guild = Guild(data=source_serialised, state=state)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<Template code={0.code!r} uses={0.uses} name={0.name!r}' \
|
||||||
|
' creator={0.creator!r} source_guild={0.source_guild!r}>'.format(self)
|
||||||
|
|
||||||
|
async def create_guild(self, name, region=None, icon=None):
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Creates a :class:`.Guild` using the template.
|
||||||
|
|
||||||
|
Bot accounts in more than 10 guilds are not allowed to create guilds.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
name: :class:`str`
|
||||||
|
The name of the guild.
|
||||||
|
region: :class:`.VoiceRegion`
|
||||||
|
The region for the voice communication server.
|
||||||
|
Defaults to :attr:`.VoiceRegion.us_west`.
|
||||||
|
icon: :class:`bytes`
|
||||||
|
The :term:`py:bytes-like object` representing the icon. See :meth:`.ClientUser.edit`
|
||||||
|
for more details on what is expected.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
:exc:`.HTTPException`
|
||||||
|
Guild creation failed.
|
||||||
|
:exc:`.InvalidArgument`
|
||||||
|
Invalid icon image format given. Must be PNG or JPG.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
:class:`.Guild`
|
||||||
|
The guild created. This is not the same guild that is
|
||||||
|
added to cache.
|
||||||
|
"""
|
||||||
|
if icon is not None:
|
||||||
|
icon = _bytes_to_base64_data(icon)
|
||||||
|
|
||||||
|
if region is None:
|
||||||
|
region = VoiceRegion.us_west.value
|
||||||
|
else:
|
||||||
|
region = region.value
|
||||||
|
|
||||||
|
data = await self._state.http.create_from_template(self.code, name, region, icon)
|
||||||
|
return Guild(data=data, state=self._sate)
|
@ -451,6 +451,17 @@ def resolve_invite(invite):
|
|||||||
return m.group(1)
|
return m.group(1)
|
||||||
return invite
|
return invite
|
||||||
|
|
||||||
|
def resolve_template(code):
|
||||||
|
from .template import Template # circular import
|
||||||
|
if isinstance(code, (Template, Object)):
|
||||||
|
return template.id
|
||||||
|
else:
|
||||||
|
rx = r'(?:https?\:\/\/)?discord(?:\.new|(?:app)?\.com\/template)\/(.+)'
|
||||||
|
m = re.match(rx, code)
|
||||||
|
if m:
|
||||||
|
return m.group(1)
|
||||||
|
return code
|
||||||
|
|
||||||
_MARKDOWN_ESCAPE_SUBREGEX = '|'.join(r'\{0}(?=([\s\S]*((?<!\{0})\{0})))'.format(c)
|
_MARKDOWN_ESCAPE_SUBREGEX = '|'.join(r'\{0}(?=([\s\S]*((?<!\{0})\{0})))'.format(c)
|
||||||
for c in ('*', '`', '_', '~', '|'))
|
for c in ('*', '`', '_', '~', '|'))
|
||||||
|
|
||||||
|
@ -2625,6 +2625,12 @@ Invite
|
|||||||
.. autoclass:: Invite()
|
.. autoclass:: Invite()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
Template
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: Template()
|
||||||
|
:members:
|
||||||
|
|
||||||
WidgetChannel
|
WidgetChannel
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user