Skip to content

Commit 0e08e82

Browse files
authored
feat: add missing args to Guild.create_forum_post (#1417)
* feat: add missing args to Guild.create_forum_post * feat: make non-name args kwarg only and optional * feat: make proper DefaultReaction class This class is barebones right now, but gets the job done. --------- Co-authored-by: Astrea49 <25420078+Astrea49@users.noreply.github.com>
1 parent a9c6ba2 commit 0e08e82

File tree

6 files changed

+130
-5
lines changed

6 files changed

+130
-5
lines changed

interactions/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
CustomEmojiConverter,
114114
DateTrigger,
115115
DefaultNotificationLevel,
116+
DefaultReaction,
116117
DM,
117118
dm_only,
118119
DMChannel,
@@ -233,12 +234,14 @@
233234
process_color,
234235
process_colour,
235236
process_components,
237+
process_default_reaction,
236238
process_embeds,
237239
process_emoji,
238240
process_emoji_req_format,
239241
process_message_payload,
240242
process_message_reference,
241243
process_permission_overwrites,
244+
process_thread_tag,
242245
Reaction,
243246
ReactionUsers,
244247
Resolved,
@@ -425,6 +428,7 @@
425428
"CustomEmojiConverter",
426429
"DateTrigger",
427430
"DefaultNotificationLevel",
431+
"DefaultReaction",
428432
"DISCORD_EPOCH",
429433
"DM",
430434
"dm_only",
@@ -564,12 +568,14 @@
564568
"process_color",
565569
"process_colour",
566570
"process_components",
571+
"process_default_reaction",
567572
"process_embeds",
568573
"process_emoji",
569574
"process_emoji_req_format",
570575
"process_message_payload",
571576
"process_message_reference",
572577
"process_permission_overwrites",
578+
"process_thread_tag",
573579
"Reaction",
574580
"ReactionUsers",
575581
"Resolved",

interactions/models/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
ComponentType,
4545
CustomEmoji,
4646
DefaultNotificationLevel,
47+
DefaultReaction,
4748
DM,
4849
DMChannel,
4950
DMGroup,
@@ -117,12 +118,14 @@
117118
process_color,
118119
process_colour,
119120
process_components,
121+
process_default_reaction,
120122
process_embeds,
121123
process_emoji,
122124
process_emoji_req_format,
123125
process_message_payload,
124126
process_message_reference,
125127
process_permission_overwrites,
128+
process_thread_tag,
126129
Reaction,
127130
ReactionUsers,
128131
Role,
@@ -373,6 +376,7 @@
373376
"CustomEmojiConverter",
374377
"DateTrigger",
375378
"DefaultNotificationLevel",
379+
"DefaultReaction",
376380
"DM",
377381
"dm_only",
378382
"DMChannel",
@@ -493,12 +497,14 @@
493497
"process_color",
494498
"process_colour",
495499
"process_components",
500+
"process_default_reaction",
496501
"process_embeds",
497502
"process_emoji",
498503
"process_emoji_req_format",
499504
"process_message_payload",
500505
"process_message_reference",
501506
"process_permission_overwrites",
507+
"process_thread_tag",
502508
"Reaction",
503509
"ReactionUsers",
504510
"Resolved",

interactions/models/discord/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@
160160
from .stage_instance import StageInstance
161161
from .sticker import Sticker, StickerItem, StickerPack
162162
from .team import Team, TeamMember
163-
from .thread import ThreadList, ThreadMember, ThreadTag
163+
from .thread import ThreadList, ThreadMember, ThreadTag, DefaultReaction, process_thread_tag, process_default_reaction
164164
from .timestamp import Timestamp, TimestampStyles
165165
from .user import BaseUser, Member, User, ClientUser
166166
from .voice_state import VoiceRegion, VoiceState
@@ -211,6 +211,7 @@
211211
"ComponentType",
212212
"CustomEmoji",
213213
"DefaultNotificationLevel",
214+
"DefaultReaction",
214215
"DM",
215216
"DMChannel",
216217
"DMGroup",
@@ -284,12 +285,14 @@
284285
"process_color",
285286
"process_colour",
286287
"process_components",
288+
"process_default_reaction",
287289
"process_embeds",
288290
"process_emoji",
289291
"process_emoji_req_format",
290292
"process_message_payload",
291293
"process_message_reference",
292294
"process_permission_overwrites",
295+
"process_thread_tag",
293296
"Reaction",
294297
"ReactionUsers",
295298
"Role",

interactions/models/discord/channel.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
to_optional_snowflake,
2424
SnowflakeObject,
2525
)
26-
from interactions.models.discord.thread import ThreadTag
26+
from interactions.models.discord.thread import DefaultReaction, ThreadTag
2727
from interactions.models.misc.context_manager import Typing
2828
from interactions.models.misc.iterator import AsyncIterator
2929
from .enums import (
@@ -2388,6 +2388,8 @@ async def close_stage(self, reason: Absent[Optional[str]] = MISSING) -> None:
23882388
class GuildForum(GuildChannel):
23892389
available_tags: List[ThreadTag] = attrs.field(repr=False, factory=list)
23902390
"""A list of tags available to assign to threads"""
2391+
default_reaction_emoji: Optional[DefaultReaction] = attrs.field(repr=False, default=None)
2392+
"""The default emoji to react with for posts"""
23912393
last_message_id: Optional[Snowflake_Type] = attrs.field(repr=False, default=None)
23922394
# TODO: Implement "template" once the API supports them
23932395

interactions/models/discord/guild.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from interactions.client.const import Absent, MISSING, PREMIUM_GUILD_LIMITS
1313
from interactions.client.errors import EventLocationNotProvided, NotFound
1414
from interactions.client.mixins.serialization import DictSerializationMixin
15-
from interactions.client.utils.attr_converters import optional
15+
from interactions.client.utils.attr_converters import optional, list_converter
1616
from interactions.client.utils.attr_converters import timestamp_converter
1717
from interactions.client.utils.attr_utils import docs
1818
from interactions.client.utils.deserialise_app_cmds import deserialize_app_cmds
@@ -1011,6 +1011,8 @@ async def create_forum_channel(
10111011
category: Union[Snowflake_Type, "models.GuildCategory"] = None,
10121012
nsfw: bool = False,
10131013
rate_limit_per_user: int = 0,
1014+
default_reaction_emoji: Absent[Union[dict, "models.PartialEmoji", "models.DefaultReaction", str]] = MISSING,
1015+
available_tags: Absent["list[dict | models.ThreadTag] | dict | models.ThreadTag"] = MISSING,
10141016
layout: ForumLayoutType = ForumLayoutType.NOT_SET,
10151017
reason: Absent[Optional[str]] = MISSING,
10161018
) -> "models.GuildForum":
@@ -1025,6 +1027,8 @@ async def create_forum_channel(
10251027
category: The category this forum channel should be within
10261028
nsfw: Should this forum be marked nsfw
10271029
rate_limit_per_user: The time users must wait between sending messages
1030+
default_reaction_emoji: The default emoji to react with when creating a thread
1031+
available_tags: The available tags for this forum channel
10281032
layout: The layout of the forum channel
10291033
reason: The reason for creating this channel
10301034
@@ -1041,6 +1045,8 @@ async def create_forum_channel(
10411045
category=category,
10421046
nsfw=nsfw,
10431047
rate_limit_per_user=rate_limit_per_user,
1048+
default_reaction_emoji=models.process_default_reaction(default_reaction_emoji),
1049+
available_tags=list_converter(models.process_thread_tag)(available_tags) if available_tags else MISSING,
10441050
default_forum_layout=layout,
10451051
reason=reason,
10461052
)

interactions/models/discord/thread.py

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44

55
import interactions.models as models
66
from interactions.client.const import MISSING
7+
from interactions.client.mixins.serialization import DictSerializationMixin
78
from interactions.client.mixins.send import SendMixin
89
from interactions.client.utils.attr_converters import optional
910
from interactions.client.utils.attr_converters import timestamp_converter
10-
from interactions.models.discord.emoji import PartialEmoji
11+
from interactions.models.discord.emoji import PartialEmoji, process_emoji
1112
from interactions.models.discord.snowflake import to_snowflake
1213
from interactions.models.discord.timestamp import Timestamp
1314
from .base import DiscordObject, ClientObject
@@ -25,6 +26,9 @@
2526
"ThreadMember",
2627
"ThreadList",
2728
"ThreadTag",
29+
"DefaultReaction",
30+
"process_thread_tag",
31+
"process_default_reaction",
2832
)
2933

3034

@@ -122,11 +126,46 @@ class ThreadTag(DiscordObject):
122126
name: str = attrs.field(
123127
repr=False,
124128
)
125-
emoji_id: "Snowflake_Type" = attrs.field(repr=False, default=None)
129+
moderated: bool = attrs.field(repr=False)
130+
emoji_id: "Snowflake_Type | None" = attrs.field(repr=False, default=None)
126131
emoji_name: str | None = attrs.field(repr=False, default=None)
127132

128133
_parent_channel_id: "Snowflake_Type" = attrs.field(repr=False, default=MISSING)
129134

135+
@classmethod
136+
def create(
137+
cls,
138+
name: str,
139+
*,
140+
moderated: bool = False,
141+
emoji: Union["models.PartialEmoji", dict, str, None] = None,
142+
) -> "ThreadTag":
143+
"""
144+
Create a new thread tag - this is useful if you're making a new forum
145+
146+
!!! warning
147+
This does not create the tag on Discord, it only creates a local object
148+
Do not expect the tag to contain valid values or for its methods to work
149+
150+
Args:
151+
name: The name for this tag
152+
moderated: Whether this tag is moderated
153+
emoji: The emoji for this tag
154+
155+
Returns:
156+
This object
157+
"""
158+
if emoji := models.process_emoji(emoji):
159+
return cls(
160+
client=None,
161+
moderated=moderated,
162+
id=0,
163+
name=name,
164+
emoji_id=emoji.get("id"),
165+
emoji_name=emoji.get("name"),
166+
)
167+
return cls(client=None, moderated=moderated, id=0, name=name)
168+
130169
@property
131170
def parent_channel(self) -> "GuildForum":
132171
"""The parent forum for this tag."""
@@ -170,3 +209,66 @@ async def delete(self) -> None:
170209
"""Delete this tag."""
171210
data = await self._client.http.delete_tag(self._parent_channel_id, self.id)
172211
self._client.cache.place_channel_data(data)
212+
213+
214+
@attrs.define(eq=False, order=False, hash=False, kw_only=True)
215+
class DefaultReaction(DictSerializationMixin):
216+
"""Represents a default reaction for a forum."""
217+
218+
emoji_id: "Snowflake_Type | None" = attrs.field(default=None)
219+
emoji_name: str | None = attrs.field(default=None)
220+
221+
@classmethod
222+
def from_emoji(cls, emoji: PartialEmoji) -> "DefaultReaction":
223+
"""Create a default reaction from an emoji."""
224+
if emoji.id:
225+
return cls(emoji_id=emoji.id)
226+
return cls(emoji_name=emoji.name)
227+
228+
229+
def process_thread_tag(tag: Optional[dict | ThreadTag]) -> Optional[dict]:
230+
"""
231+
Processes the tag parameter into the dictionary format required by the API.
232+
233+
Args:
234+
tag: The tag to process
235+
236+
Returns:
237+
formatted dictionary for discrd
238+
"""
239+
if not tag:
240+
return tag
241+
242+
if isinstance(tag, ThreadTag):
243+
return tag.to_dict()
244+
245+
if isinstance(tag, dict):
246+
return tag
247+
248+
raise ValueError(f"Invalid tag: {tag}")
249+
250+
251+
def process_default_reaction(reaction: Optional[dict | DefaultReaction | PartialEmoji | str]) -> Optional[dict]:
252+
"""
253+
Processes the reaction parameter into the dictionary format required by the API.
254+
255+
Args:
256+
reaction: The reaction to process.
257+
258+
Returns:
259+
formatted dictionary for discrd
260+
"""
261+
if not reaction:
262+
return reaction
263+
264+
if isinstance(reaction, dict):
265+
return reaction
266+
267+
if not isinstance(reaction, DefaultReaction):
268+
emoji = process_emoji(reaction)
269+
if emoji_id := emoji.get("id"):
270+
reaction = DefaultReaction(emoji_id=emoji_id)
271+
else:
272+
reaction = DefaultReaction(emoji_name=emoji["name"])
273+
274+
return reaction.to_dict()

0 commit comments

Comments
 (0)