Skip to content

Commit bc44bb6

Browse files
committed
feat: Add guild onboarding settings
1 parent 670a47b commit bc44bb6

File tree

7 files changed

+272
-0
lines changed

7 files changed

+272
-0
lines changed

interactions/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,11 @@
224224
NoArgumentConverter,
225225
NSFWLevel,
226226
open_file,
227+
Onboarding,
228+
OnboardingMode,
229+
OnboardingPrompt,
230+
OnboardingPromptOption,
231+
OnboardingPromptType,
227232
OptionType,
228233
OrTrigger,
229234
OverwriteType,
@@ -564,6 +569,11 @@
564569
"NoArgumentConverter",
565570
"NSFWLevel",
566571
"open_file",
572+
"Onboarding",
573+
"OnboardingMode",
574+
"OnboardingPrompt",
575+
"OnboardingPromptOption",
576+
"OnboardingPromptType",
567577
"OptionType",
568578
"OrTrigger",
569579
"OverwriteType",

interactions/api/http/http_requests/guild.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,3 +1041,39 @@ async def delete_auto_moderation_rule(
10411041
reason=reason,
10421042
)
10431043
return cast(dict, result)
1044+
1045+
async def get_guild_onboarding(self, guild_id: "Snowflake_Type") -> discord_typings.GuildOnboardingData:
1046+
"""
1047+
Get the guild's onboarding settings.
1048+
1049+
Args:
1050+
guild_id: The ID of the guild
1051+
1052+
Returns:
1053+
The guild's onboarding object
1054+
1055+
"""
1056+
result = await self.request(Route("GET", "/guilds/{guild_id}/onboarding", guild_id=guild_id))
1057+
return cast(discord_typings.GuildOnboardingData, result)
1058+
1059+
async def modify_guild_onboarding(
1060+
self, guild_id: "Snowflake_Type", payload: dict, reason: str | None = None
1061+
) -> discord_typings.GuildOnboardingData:
1062+
"""
1063+
Modify the guild's onboarding settings.
1064+
1065+
Args:
1066+
guild_id: The ID of the guild
1067+
payload: A dict representing the modified Onboarding
1068+
reason: The reason for this action
1069+
1070+
Returns:
1071+
The updated onboarding object
1072+
1073+
"""
1074+
result = await self.request(
1075+
Route("PUT", "/guilds/{guild_id}/onboarding", guild_id=guild_id),
1076+
payload=payload,
1077+
reason=reason,
1078+
)
1079+
return cast(discord_typings.GuildOnboardingData, result)

interactions/models/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@
110110
NSFWLevel,
111111
open_file,
112112
OverwriteType,
113+
Onboarding,
114+
OnboardingMode,
115+
OnboardingPrompt,
116+
OnboardingPromptOption,
117+
OnboardingPromptType,
113118
ParagraphText,
114119
PartialEmoji,
115120
PermissionOverwrite,
@@ -493,6 +498,11 @@
493498
"NoArgumentConverter",
494499
"NSFWLevel",
495500
"open_file",
501+
"Onboarding",
502+
"OnboardingMode",
503+
"OnboardingPrompt",
504+
"OnboardingPromptOption",
505+
"OnboardingPromptType",
496506
"OptionType",
497507
"OrTrigger",
498508
"OverwriteType",

interactions/models/discord/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@
9898
MessageType,
9999
MFALevel,
100100
NSFWLevel,
101+
OnboardingMode,
102+
OnboardingPromptType,
101103
OverwriteType,
102104
Permissions,
103105
PremiumTier,
@@ -149,6 +151,7 @@
149151
process_message_reference,
150152
)
151153
from .modal import InputText, Modal, ParagraphText, ShortText, TextStyles
154+
from .onboarding import Onboarding, OnboardingPrompt, OnboardingPromptOption
152155
from .reaction import Reaction, ReactionUsers
153156
from .role import Role
154157
from .scheduled_event import ScheduledEvent
@@ -280,6 +283,11 @@
280283
"Modal",
281284
"NSFWLevel",
282285
"open_file",
286+
"Onboarding",
287+
"OnboardingMode",
288+
"OnboardingPrompt",
289+
"OnboardingPromptOption",
290+
"OnboardingPromptType",
283291
"OverwriteType",
284292
"ParagraphText",
285293
"PartialEmoji",

interactions/models/discord/enums.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
"MessageType",
3333
"MFALevel",
3434
"NSFWLevel",
35+
"OnboardingMode",
36+
"OnboardingPromptType",
3537
"OverwriteType",
3638
"Permissions",
3739
"PremiumTier",
@@ -720,6 +722,22 @@ class MentionType(str, Enum):
720722
USERS = "users"
721723

722724

725+
class OnboardingMode(CursedIntEnum):
726+
"""Defines the criteria used to satisfy Onboarding constraints that are required for enabling."""
727+
728+
ONBOARDING_DEFAULT = 0
729+
"""Counts only Default Channels towards constraints"""
730+
ONBOARDING_ADVANCED = 1
731+
"""Counts Default Channels and Questions towards constraints"""
732+
733+
734+
class OnboardingPromptType(CursedIntEnum):
735+
"""Types of Onboarding prompts."""
736+
737+
MULTIPLE_CHOICE = 0
738+
DROPDOWN = 1
739+
740+
723741
class OverwriteType(CursedIntEnum):
724742
"""Types of permission overwrite."""
725743

interactions/models/discord/guild.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
)
2727
from interactions.models.discord.auto_mod import AutoModRule, BaseAction, BaseTrigger
2828
from interactions.models.discord.file import UPLOADABLE_TYPE
29+
from interactions.models.discord.onboarding import Onboarding
2930
from interactions.models.misc.iterator import AsyncIterator
3031

3132
from .base import ClientObject, DiscordObject
@@ -2035,6 +2036,16 @@ async def fetch_voice_regions(self) -> List["models.VoiceRegion"]:
20352036
regions_data = await self._client.http.get_guild_voice_regions(self.id)
20362037
return models.VoiceRegion.from_list(regions_data)
20372038

2039+
async def fetch_onboarding(self) -> Onboarding:
2040+
"""
2041+
Fetches the guild's onboarding settings.
2042+
2043+
Returns:
2044+
The guild's onboarding settings.
2045+
2046+
"""
2047+
return Onboarding.from_dict(await self._client.http.get_guild_onboarding(self.id), self._client)
2048+
20382049
@property
20392050
def gui_sorted_channels(self) -> list["models.TYPE_GUILD_CHANNEL"]:
20402051
"""Return this guilds channels sorted by their gui positions"""
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
from typing import Any, Dict, List, Optional, Union
2+
3+
import attrs
4+
5+
from interactions.client.const import MISSING, Absent
6+
from interactions.client.mixins.serialization import DictSerializationMixin
7+
from interactions.client.utils.attr_converters import optional
8+
from interactions.models.discord.base import ClientObject
9+
from interactions.models.discord.emoji import PartialEmoji, process_emoji
10+
from interactions.models.discord.enums import OnboardingMode, OnboardingPromptType
11+
from interactions.models.discord.snowflake import (
12+
Snowflake,
13+
Snowflake_Type,
14+
SnowflakeObject,
15+
to_snowflake,
16+
to_snowflake_list,
17+
)
18+
19+
__all__ = ("OnboardingPromptOption", "OnboardingPrompt", "Onboarding")
20+
21+
22+
@attrs.define(eq=False, order=False, hash=False, kw_only=True)
23+
class OnboardingPromptOption(SnowflakeObject, DictSerializationMixin):
24+
channel_ids: List["Snowflake"] = attrs.field(repr=False, converter=to_snowflake_list)
25+
"""IDs for channels a member is added to when the option is selected"""
26+
role_ids: List["Snowflake"] = attrs.field(repr=False, converter=to_snowflake_list)
27+
"""IDs for roles assigned to a member when the option is selected"""
28+
title: str = attrs.field(repr=False)
29+
"""Title of the option"""
30+
description: Optional[str] = attrs.field(repr=False, default=None)
31+
"""Description of the option"""
32+
emoji: Optional[PartialEmoji] = attrs.field(repr=False, default=None, converter=optional(PartialEmoji.from_dict))
33+
"""Emoji of the option"""
34+
35+
# this method is here because Discord needs the id field to be present in the payload
36+
@classmethod
37+
def create(
38+
cls,
39+
title: str,
40+
*,
41+
channel_ids: Optional[List[Snowflake_Type]] = None,
42+
role_ids: Optional[List[Snowflake_Type]] = None,
43+
description: Optional[str] = None,
44+
emoji: Optional[Union[PartialEmoji, dict, str]] = None,
45+
) -> "OnboardingPromptOption":
46+
"""
47+
Creates a new Onboarding prompt option object.
48+
49+
Args:
50+
title: Title of the option
51+
channel_ids: Channel IDs that this option represents
52+
role_ids: Role IDs that this option represents
53+
description: Description of the option
54+
emoji: Emoji of the option
55+
56+
Returns:
57+
The newly created OnboardingPromptOption object
58+
59+
"""
60+
return cls(
61+
id=0,
62+
channel_ids=channel_ids or [],
63+
role_ids=role_ids or [],
64+
title=title,
65+
description=description,
66+
emoji=process_emoji(emoji),
67+
)
68+
69+
def as_dict(self) -> Dict[str, Any]:
70+
data = {
71+
"id": self.id,
72+
"channel_ids": self.channel_ids,
73+
"role_ids": self.role_ids,
74+
"title": self.title,
75+
"description": self.description,
76+
}
77+
# use the separate fields when sending to Discord
78+
if self.emoji is not None:
79+
data["emoji_id"] = self.emoji.id
80+
data["emoji_name"] = self.emoji.name
81+
data["emoji_animated"] = self.emoji.animated
82+
return data
83+
84+
85+
@attrs.define(eq=False, order=False, hash=False, kw_only=False)
86+
class OnboardingPrompt(SnowflakeObject, DictSerializationMixin):
87+
type: OnboardingPromptType = attrs.field(repr=False, converter=OnboardingPromptType)
88+
"""Type of the prompt"""
89+
options: List[OnboardingPromptOption] = attrs.field(repr=False, converter=OnboardingPromptOption.from_list)
90+
"""Options available in the prompt"""
91+
title: str = attrs.field(repr=False)
92+
"""Title of the prompt"""
93+
single_select: bool = attrs.field(repr=False)
94+
"""Whether users are limited to selecting one option for the prompt"""
95+
required: bool = attrs.field(repr=False)
96+
"""Whether users are required to complete this prompt"""
97+
in_onboarding: bool = attrs.field(repr=False)
98+
"""Whether the prompt is present in the onboarding flow; otherwise it is only in the Channels & Roles tab"""
99+
100+
@classmethod
101+
def create(
102+
cls,
103+
*,
104+
type: Union[OnboardingPromptType, int] = OnboardingPromptType.MULTIPLE_CHOICE,
105+
options: List[OnboardingPromptOption],
106+
title: str,
107+
single_select: bool = False,
108+
required: bool = False,
109+
in_onboarding: bool = True,
110+
) -> "OnboardingPrompt":
111+
"""
112+
Creates a new Onboarding prompt object.
113+
114+
Args:
115+
type: Type of the prompt
116+
options: Options available in the prompt
117+
title: Title of the prompt
118+
single_select: Whether users are limited to selecting one option for the prompt
119+
required: Whether users are required to complete this prompt
120+
in_onboarding: Whether the prompt is present in the onboarding flow; otherwise it is only in the Channels & Roles tab
121+
122+
Returns:
123+
The newly created OnboardingPrompt object
124+
125+
"""
126+
return cls(
127+
id=0,
128+
type=type,
129+
options=options,
130+
title=title,
131+
single_select=single_select,
132+
required=required,
133+
in_onboarding=in_onboarding,
134+
)
135+
136+
137+
@attrs.define(eq=False, order=False, hash=False, kw_only=False)
138+
class Onboarding(ClientObject):
139+
"""Represents the onboarding flow for a guild."""
140+
141+
guild_id: Snowflake = attrs.field(repr=False, converter=to_snowflake)
142+
"""ID of the guild this onboarding is part of"""
143+
prompts: list[OnboardingPrompt] = attrs.field(repr=False, converter=OnboardingPrompt.from_list)
144+
"""Prompts shown during onboarding and in customize community"""
145+
default_channel_ids: list[Snowflake] = attrs.field(repr=False, converter=to_snowflake_list)
146+
"""Channel IDs that members get opted into automatically"""
147+
enabled: bool = attrs.field(repr=False)
148+
"""Whether onboarding is enabled in the guild"""
149+
mode: OnboardingMode = attrs.field(repr=False, converter=OnboardingMode)
150+
"""Current mode of onboarding"""
151+
152+
async def edit(
153+
self,
154+
*,
155+
prompts: Absent[List[OnboardingPrompt]] = MISSING,
156+
default_channel_ids: Absent[list[Snowflake_Type]] = MISSING,
157+
enabled: Absent[bool] = MISSING,
158+
mode: Absent[Union[OnboardingMode, int]] = MISSING,
159+
reason: Absent[str] = MISSING,
160+
) -> None:
161+
"""
162+
Edits this Onboarding flow.
163+
164+
Args:
165+
prompts: Prompts shown during onboarding and in customize community
166+
default_channel_ids: Channel IDs that members get opted into automatically
167+
enabled: Whether onboarding is enabled in the guild
168+
mode: Current mode of onboarding
169+
reason: The reason for this change
170+
171+
"""
172+
payload = {
173+
"prompts": prompts,
174+
"default_channel_ids": default_channel_ids,
175+
"enabled": enabled,
176+
"mode": mode,
177+
}
178+
data = await self._client.http.modify_guild_onboarding(self.guild_id, payload, reason)
179+
self.update_from_dict(data)

0 commit comments

Comments
 (0)