Skip to content

Commit b1faa17

Browse files
Merge pull request #143 from nerdguyahmad/welcome-screen
Add support for Welcome screen
2 parents fe31e46 + 6439c2f commit b1faa17

File tree

5 files changed

+351
-0
lines changed

5 files changed

+351
-0
lines changed

discord/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
from .threads import *
6262
from .bot import *
6363
from .app import *
64+
from .welcome_screen import *
6465

6566

6667
class VersionInfo(NamedTuple):

discord/guild.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
from .threads import Thread, ThreadMember
7777
from .sticker import GuildSticker
7878
from .file import File
79+
from .welcome_screen import WelcomeScreen, WelcomeScreenChannel
7980

8081

8182
__all__ = (
@@ -2942,3 +2943,101 @@ async def change_voice_state(
29422943
ws = self._state._get_websocket(self.id)
29432944
channel_id = channel.id if channel else None
29442945
await ws.voice_state(self.id, channel_id, self_mute, self_deaf)
2946+
2947+
async def welcome_screen(self):
2948+
"""|coro|
2949+
2950+
Returns the :class:`WelcomeScreen` of the guild.
2951+
2952+
The guild must have ``COMMUNITY`` in :attr:`~Guild.features`.
2953+
2954+
You must have the :attr:`~Permissions.manage_guild` permission in order to get this.
2955+
2956+
.. versionadded:: 2.0
2957+
2958+
Raises
2959+
-------
2960+
Forbidden
2961+
You do not have the proper permissions to get this.
2962+
HTTPException
2963+
Retrieving the welcome screen failed somehow.
2964+
NotFound
2965+
The guild doesn't has a welcome screen or community feature is disabled.
2966+
2967+
2968+
Returns
2969+
--------
2970+
:class:`WelcomeScreen`
2971+
The welcome screen of guild.
2972+
"""
2973+
data = await self._state.http.get_welcome_screen(self.id)
2974+
return WelcomeScreen(data=data, guild=self)
2975+
2976+
2977+
@overload
2978+
async def edit_welcome_screen(
2979+
self,
2980+
*,
2981+
description: Optional[str] = ...,
2982+
welcome_channels: Optional[List[WelcomeChannel]] = ...,
2983+
enabled: Optional[bool] = ...,
2984+
) -> WelcomeScreen:
2985+
...
2986+
2987+
@overload
2988+
async def edit_welcome_screen(self) -> None:
2989+
...
2990+
2991+
2992+
async def edit_welcome_screen(self, **options):
2993+
"""|coro|
2994+
2995+
A shorthand for :attr:`WelcomeScreen.edit` without fetching the welcome screen.
2996+
2997+
You must have the :attr:`~Permissions.manage_guild` permission in the
2998+
guild to do this.
2999+
3000+
The guild must have ``COMMUNITY`` in :attr:`Guild.features`
3001+
3002+
Parameters
3003+
------------
3004+
3005+
description: Optional[:class:`str`]
3006+
The new description of welcome screen.
3007+
welcome_channels: Optional[List[:class:`WelcomeChannel`]]
3008+
The welcome channels. The order of the channels would be same as the passed list order.
3009+
enabled: Optional[:class:`bool`]
3010+
Whether the welcome screen should be displayed.
3011+
3012+
Raises
3013+
-------
3014+
3015+
HTTPException
3016+
Editing the welcome screen failed somehow.
3017+
Forbidden
3018+
You don't have permissions to edit the welcome screen.
3019+
NotFound
3020+
This welcome screen does not exist.
3021+
3022+
Returns
3023+
--------
3024+
3025+
:class:`WelcomeScreen`
3026+
The edited welcome screen.
3027+
"""
3028+
3029+
welcome_channels = options.get('welcome_channels', [])
3030+
welcome_channels_data = []
3031+
3032+
for channel in welcome_channels:
3033+
if not isinstance(channel, WelcomeScreenChannel):
3034+
raise TypeError('welcome_channels parameter must be a list of WelcomeScreenChannel.')
3035+
3036+
welcome_channels_data.append(channel.to_dict())
3037+
3038+
options['welcome_channels'] = welcome_channels_data
3039+
3040+
if options:
3041+
new = await self._state.http.edit_welcome_screen(self.id, options)
3042+
return WelcomeScreen(data=new, guild=self)
3043+

discord/http.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,6 +1490,22 @@ def delete_channel_permissions(
14901490
) -> Response[None]:
14911491
r = Route('DELETE', '/channels/{channel_id}/permissions/{target}', channel_id=channel_id, target=target)
14921492
return self.request(r, reason=reason)
1493+
1494+
# Welcome Screen
1495+
1496+
def get_welcome_screen(self, guild_id: Snowflake) -> Response[welcome_screen.WelcomeScreen]:
1497+
return self.request(Route('GET', '/guilds/{guild_id}/welcome-screen', guild_id=guild_id))
1498+
1499+
def edit_welcome_screen(self, guild_id: Snowflake, payload: Any) -> Response[welcome_screen.WelcomeScreen]:
1500+
keys = (
1501+
'description',
1502+
'welcome_channels',
1503+
'enabled',
1504+
)
1505+
payload = {
1506+
key: val for key, val in payload.items() if key in keys
1507+
}
1508+
return self.request(Route('PATCH', '/guilds/{guild_id}/welcome-screen', guild_id=guild_id), json=payload)
14931509

14941510
# Voice management
14951511

discord/welcome_screen.py

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
"""
2+
The MIT License (MIT)
3+
4+
Copyright (c) 2015-present Rapptz
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a
7+
copy of this software and associated documentation files (the "Software"),
8+
to deal in the Software without restriction, including without limitation
9+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
10+
and/or sell copies of the Software, and to permit persons to whom the
11+
Software is furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22+
DEALINGS IN THE SOFTWARE.
23+
"""
24+
25+
from __future__ import annotations
26+
27+
from typing import TYPE_CHECKING, List, Union, overload
28+
from .utils import _get_as_snowflake, get
29+
from .partial_emoji import _EmojiTag
30+
31+
if TYPE_CHECKING:
32+
from .types.welcome_screen import (
33+
WelcomeScreen as WelcomeScreenPayload,
34+
WelcomeScreenChannel as WelcomeScreenChannelPayload,
35+
)
36+
from .guild import Guild
37+
from .abc import Snowflake
38+
from .partial_emoji import PartialEmoji
39+
from .emoji import Emoji
40+
41+
__all__ = (
42+
'WelcomeScreen',
43+
'WelcomeScreenChannel',
44+
)
45+
46+
class WelcomeScreenChannel:
47+
"""Represents a welcome channel displayed on :class:`WelcomeScreen`
48+
49+
.. versionadded:: 2.0
50+
51+
Attributes
52+
----------
53+
54+
channel: :class:`abc.Snowflake`
55+
The channel that is being referenced.
56+
description: :class:`str`
57+
The description of channel that is shown on the welcome screen.
58+
emoji: :class:`Union[Emoji, PartialEmoji, str]`
59+
The emoji of channel that is shown on welcome screen.
60+
"""
61+
def __init__(self, channel: Snowflake, description: str, emoji: Union[Emoji, PartialEmoji, str]):
62+
self.channel = channel
63+
self.description = description
64+
self.emoji = emoji
65+
66+
def __repr__(self):
67+
return f'WelcomeScreenChannel(channel={self.channel} description={self.description})'
68+
69+
def to_dict(self) -> WelcomeScreenChannelPayload:
70+
dict_: WelcomeScreenChannelPayload = {
71+
'channel_id': self.channel.id,
72+
'description': self.description,
73+
'emoji_id': None,
74+
'emoji_name': None,
75+
}
76+
77+
if isinstance(self.emoji, _EmojiTag):
78+
# custom guild emoji
79+
dict_['emoji_id'] = self.emoji.id # type: ignore
80+
dict_['emoji_name'] = self.emoji.name # type: ignore
81+
else:
82+
# unicode emoji or None
83+
dict_['emoji_name'] = self.emoji
84+
dict_['emoji_id'] = None # type: ignore
85+
86+
return dict_
87+
88+
89+
@classmethod
90+
def _from_dict(cls, data: WelcomeScreenChannelPayload, guild: Guild) -> WelcomeChannel:
91+
channel_id = _get_as_snowflake(data, 'channel_id')
92+
channel = guild.get_channel(channel_id)
93+
description = data.get('description')
94+
_emoji_id = _get_as_snowflake(data, 'emoji_id')
95+
_emoji_name = data.get('emoji_name')
96+
97+
if _emoji_id:
98+
# custom guild emoji
99+
emoji = get(guild.emojis, id=_emoji_id)
100+
else:
101+
# unicode emoji or None
102+
emoji = _emoji_name
103+
104+
return cls(channel=channel, description=description, emoji=emoji) # type: ignore
105+
106+
107+
108+
class WelcomeScreen:
109+
"""Represents the welcome screen of a guild.
110+
111+
.. versionadded:: 2.0
112+
113+
Attributes
114+
----------
115+
116+
description: :class:`str`
117+
The description text displayed on the welcome screen.
118+
welcome_channels: List[:class:`WelcomeScreenChannel`]
119+
A list of channels displayed on welcome screen.
120+
"""
121+
122+
def __init__(self, data: WelcomeScreenPayload, guild: Guild):
123+
self._guild = guild
124+
self._update(data)
125+
126+
def __repr__(self):
127+
return f'<WelcomeScreen description={self.description} welcome_channels={self.welcome_channels}'
128+
129+
def _update(self, data: WelcomeScreenPayload):
130+
self.description: str = data.get('description')
131+
self.welcome_channels: List[WelcomeScreenChannel] = [WelcomeScreenChannel._from_dict(channel, self._guild) for channel in data.get('welcome_channels', [])]
132+
133+
134+
@property
135+
def enabled(self) -> bool:
136+
""":class:`bool`: Indicates whether the welcome screen is enabled or not."""
137+
return 'WELCOME_SCREEN_ENABLED' in self._guild.features
138+
139+
@property
140+
def guild(self) -> Guild:
141+
""":class:`Guild`: The guild this welcome screen belongs to."""
142+
return self._guild
143+
144+
145+
@overload
146+
async def edit(
147+
self,
148+
*,
149+
description: Optional[str] = ...,
150+
welcome_channels: Optional[List[WelcomeChannel]] = ...,
151+
enabled: Optional[bool] = ...,
152+
) -> None:
153+
...
154+
155+
@overload
156+
async def edit(self) -> None:
157+
...
158+
159+
async def edit(self, **options):
160+
"""|coro|
161+
162+
Edits the welcome screen.
163+
164+
You must have the :attr:`~Permissions.manage_guild` permission in the
165+
guild to do this.
166+
167+
Usage: ::
168+
rules_channel = guild.get_channel(12345678)
169+
announcements_channel = guild.get_channel(87654321)
170+
custom_emoji = utils.get(guild.emojis, name='loudspeaker')
171+
await welcome_screen.edit(
172+
description='This is a very cool community server!',
173+
welcome_channels=[
174+
WelcomeChannel(channel=rules_channel, description='Read the rules!', emoji='👨‍🏫'),
175+
WelcomeChannel(channel=announcements_channel, description='Watch out for announcements!', emoji=custom_emoji),
176+
]
177+
)
178+
179+
.. note::
180+
Welcome channels can only accept custom emojis if :attr:`~Guild.premium_tier` is level 2 or above.
181+
182+
Parameters
183+
------------
184+
185+
description: Optional[:class:`str`]
186+
The new description of welcome screen.
187+
welcome_channels: Optional[List[:class:`WelcomeChannel`]]
188+
The welcome channels. The order of the channels would be same as the passed list order.
189+
enabled: Optional[:class:`bool`]
190+
Whether the welcome screen should be displayed.
191+
192+
Raises
193+
-------
194+
195+
HTTPException
196+
Editing the welcome screen failed somehow.
197+
Forbidden
198+
You don't have permissions to edit the welcome screen.
199+
NotFound
200+
This welcome screen does not exist.
201+
202+
"""
203+
204+
welcome_channels = options.get('welcome_channels', [])
205+
welcome_channels_data = []
206+
207+
for channel in welcome_channels:
208+
if not isinstance(channel, WelcomeScreenChannel):
209+
raise TypeError('welcome_channels parameter must be a list of WelcomeScreenChannel.')
210+
211+
welcome_channels_data.append(channel.to_dict())
212+
213+
options['welcome_channels'] = welcome_channels_data
214+
215+
if options:
216+
new = await self._guild._state.http.edit_welcome_screen(self._guild.id, options)
217+
self._update(new)
218+
219+
return self

docs/api.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3831,6 +3831,22 @@ Template
38313831

38323832
.. autoclass:: Template()
38333833
:members:
3834+
3835+
WelcomeScreen
3836+
~~~~~~~~~~~~~~~
3837+
3838+
.. attributetable:: WelcomeScreen
3839+
3840+
.. autoclass:: WelcomeScreen()
3841+
:members:
3842+
3843+
WelcomeScreenChannel
3844+
~~~~~~~~~~~~~~~
3845+
3846+
.. attributetable:: WelcomeScreenChannel
3847+
3848+
.. autoclass:: WelcomeScreenChannel()
3849+
:members:
38343850

38353851
WidgetChannel
38363852
~~~~~~~~~~~~~~~

0 commit comments

Comments
 (0)