diff --git a/src/Discord/Builders/CommandAttributes.php b/src/Discord/Builders/CommandAttributes.php index 4f02e1540..1954b57dc 100644 --- a/src/Discord/Builders/CommandAttributes.php +++ b/src/Discord/Builders/CommandAttributes.php @@ -63,8 +63,10 @@ public function setType(int $type): self public function setName(string $name): self { $nameLen = poly_strlen($name); - if ($nameLen < 1 || $nameLen > 100) { - throw new \LengthException('Command name can be only 1 to 32 characters long.'); + if ($nameLen < 1) { + throw new \LengthException('Command name can not be empty.'); + } elseif ($nameLen > 32) { + throw new \LengthException('Command name can be only up to 32 characters long.'); } $this->name = $name; @@ -86,8 +88,10 @@ public function setNameLocalization(string $locale, ?string $name): self { if (isset($name)) { $nameLen = poly_strlen($name); - if ($nameLen < 1 || $nameLen > 100) { - throw new \LengthException('Command name can be only 1 to 32 characters long.'); + if ($nameLen < 1) { + throw new \LengthException('Command name can not be empty.'); + } elseif ($nameLen > 32) { + throw new \LengthException('Command name can be only up to 32 characters long.'); } } @@ -108,8 +112,10 @@ public function setNameLocalization(string $locale, ?string $name): self public function setDescription(string $description): self { $descriptionLen = poly_strlen($description); - if ($descriptionLen < 1 || $descriptionLen > 100) { - throw new \LengthException('Command Description can be only 1 to 100 characters long.'); + if ($descriptionLen < 1) { + throw new \LengthException('Command description can not be empty.'); + } elseif ($descriptionLen > 100) { + throw new \LengthException('Command description can be only up to 100 characters long.'); } $this->description = $description; @@ -202,8 +208,6 @@ public function removeOption(Option $option): self /** * Clear all options from the command. * - * @throws \DomainException - * * @return $this */ public function clearOptions(): self diff --git a/src/Discord/Builders/MessageBuilder.php b/src/Discord/Builders/MessageBuilder.php index ffa263c22..fafc36f58 100644 --- a/src/Discord/Builders/MessageBuilder.php +++ b/src/Discord/Builders/MessageBuilder.php @@ -474,7 +474,7 @@ public function getStickers(): array /** * Sets the flags of the message. * - * @internal You cannot set flags except for when sending webhooks. Use the APIs given. + * @internal You cannot set flags except for when sending webhooks or interaction. Use the APIs given. * * @param int $flags * diff --git a/src/Discord/Parts/Channel/Channel.php b/src/Discord/Parts/Channel/Channel.php index c25175c3b..cd1745c9c 100644 --- a/src/Discord/Parts/Channel/Channel.php +++ b/src/Discord/Parts/Channel/Channel.php @@ -57,7 +57,7 @@ * @property string|null $name The name of the channel. * @property string|null $topic The topic of the channel. * @property bool|null $nsfw Whether the channel is NSFW. - * @property string|null $last_message_id The unique identifier of the last message sent in the channel. + * @property string|null $last_message_id The unique identifier of the last message sent in the channel (or thread for forum channels) (may not point to an existing or valid message or thread). * @property int|null $bitrate The bitrate of the channel. Only for voice channels. * @property int|null $user_limit The user limit of the channel. * @property int|null $rate_limit_per_user Amount of seconds a user has to wait before sending a new message. @@ -72,6 +72,7 @@ * @property string|null $rtc_region Voice region id for the voice channel, automatic when set to null. * @property int|null $video_quality_mode The camera video quality mode of the voice channel, 1 when not present. * @property int|null $default_auto_archive_duration Default duration for newly created threads, in minutes, to automatically archive the thread after recent activity, can be set to: 60, 1440, 4320, 10080. + * @property int|null $flags Channel flags combined as a bitfield. * @property string|null $permissions Computed permissions for the invoking user in the channel, including overwrites, only included when part of the resolved data received on a slash command interaction. * @property bool $is_private Whether the channel is a private channel. * @property MemberRepository $members Voice channel only - members in the channel. @@ -98,10 +99,13 @@ class Channel extends Part public const TYPE_PRIVATE_THREAD = 12; public const TYPE_STAGE_CHANNEL = 13; public const TYPE_DIRECTORY = 14; + public const TYPE_FORUM = 15; public const VIDEO_QUALITY_AUTO = 1; public const VIDEO_QUALITY_FULL = 2; + public const FLAG_PINNED = (1 << 1); + /** * @inheritdoc */ @@ -128,6 +132,7 @@ class Channel extends Part 'video_quality_mode', 'default_auto_archive_duration', 'permissions', + 'flags', 'is_private', ]; @@ -763,9 +768,9 @@ protected function setPermissionOverwritesAttribute(array $overwrites): void * * @see https://discord.com/developers/docs/resources/channel#start-thread-without-message * - * @param string $name the name of the thread. - * @param bool $private whether the thread should be private. cannot start a private thread in a news channel. - * @param int $auto_archive_duration number of minutes of inactivity until the thread is auto-archived. one of 60, 1440, 4320, 10080. + * @param string $name The name of the thread. + * @param bool $private Whether the thread should be private. cannot start a private thread in a news channel or forum channel. + * @param int $auto_archive_duration Number of minutes of inactivity until the thread is auto-archived. one of 60, 1440, 4320, 10080. * @param string|null $reason Reason for Audit Log. * * @throws \RuntimeException @@ -787,6 +792,8 @@ public function startThread(string $name, bool $private = false, int $auto_archi $type = Channel::TYPE_NEWS_THREAD; } elseif ($this->type == Channel::TYPE_TEXT) { $type = $private ? Channel::TYPE_PRIVATE_THREAD : Channel::TYPE_PUBLIC_THREAD; + } elseif ($this->type == Channel::TYPE_FORUM) { + $type = Channel::TYPE_PUBLIC_THREAD; } else { return reject(new \RuntimeException('You cannot start a thread in this type of channel.')); } @@ -1061,7 +1068,7 @@ public function allowVoice() */ public function allowInvite() { - return in_array($this->type, [self::TYPE_TEXT, self::TYPE_VOICE, self::TYPE_NEWS, self::TYPE_STAGE_CHANNEL]); + return in_array($this->type, [self::TYPE_TEXT, self::TYPE_VOICE, self::TYPE_NEWS, self::TYPE_STAGE_CHANNEL, self::TYPE_FORUM]); } /** diff --git a/src/Discord/Parts/Channel/Message.php b/src/Discord/Parts/Channel/Message.php index 86f47d91c..c18155d86 100644 --- a/src/Discord/Parts/Channel/Message.php +++ b/src/Discord/Parts/Channel/Message.php @@ -118,6 +118,9 @@ class Message extends Part public const REACT_DELETE_ID = 2; public const REACT_DELETE_EMOJI = 3; + public const FLAG_SUPPRESS_EMBED = (1 << 2); + public const FLAG_EPHEMERAL = (1 << 6); + /** * @inheritdoc */ @@ -188,7 +191,7 @@ protected function getIsCrosspostAttribute(): bool */ protected function getSuppressEmbedsAttribute(): bool { - return (bool) ($this->flags & (1 << 2)); + return (bool) ($this->flags & self::FLAG_SUPPRESS_EMBED); } /** @@ -228,7 +231,7 @@ protected function getHasThreadAttribute(): bool */ protected function getEphemeralAttribute(): bool { - return (bool) ($this->flags & (1 << 6)); + return (bool) ($this->flags & self::FLAG_EPHEMERAL); } /** diff --git a/src/Discord/Parts/Interactions/Interaction.php b/src/Discord/Parts/Interactions/Interaction.php index 839576b30..b726fae6f 100644 --- a/src/Discord/Parts/Interactions/Interaction.php +++ b/src/Discord/Parts/Interactions/Interaction.php @@ -87,6 +87,14 @@ class Interaction extends Part */ protected $responded = false; + /** + * Returns true if this interaction has been internally responded. + */ + public function isResponded(): bool + { + return $this->responded; + } + /** * Returns the data associated with the interaction. * @@ -99,7 +107,7 @@ protected function getDataAttribute(): ?InteractionData } $adata = $this->attributes['data']; - if (isset($this->attributes['guild_id'])) { + if (! isset($adata->guild_id) && isset($this->attributes['guild_id'])) { $adata->guild_id = $this->guild_id; } @@ -341,7 +349,7 @@ public function sendFollowUpMessage(MessageBuilder $builder, bool $ephemeral = f } if ($ephemeral) { - $builder->_setFlags(64); + $builder->_setFlags(Message::FLAG_EPHEMERAL); } return (function () use ($builder): ExtendedPromiseInterface { @@ -376,7 +384,7 @@ public function respondWithMessage(MessageBuilder $builder, bool $ephemeral = fa } if ($ephemeral) { - $builder->_setFlags(64); + $builder->_setFlags(Message::FLAG_EPHEMERAL); } return $this->respond([ diff --git a/src/Discord/Parts/Interactions/Request/InteractionData.php b/src/Discord/Parts/Interactions/Request/InteractionData.php index 5a3e12554..0b6dd063a 100644 --- a/src/Discord/Parts/Interactions/Request/InteractionData.php +++ b/src/Discord/Parts/Interactions/Request/InteractionData.php @@ -30,7 +30,7 @@ * @property string[]|null $values Values selected in a select menu. * @property string|null $target_id Id the of user or message targetted by a user or message command. * @property ComponentRepository $components The values submitted by the user in modal. - * @property string|null $guild_id ID of the guild passed from Interaction. + * @property string|null $guild_id ID of the guild passed from Interaction or ID of the guild the command belongs to. */ class InteractionData extends Part { diff --git a/src/Discord/Parts/User/Member.php b/src/Discord/Parts/User/Member.php index 051174a15..acc35ee7c 100644 --- a/src/Discord/Parts/User/Member.php +++ b/src/Discord/Parts/User/Member.php @@ -679,10 +679,6 @@ public function getRepositoryAttributes(): array */ public function __toString(): string { - if ($this->nick) { - return "<@!{$this->id}>"; - } - return "<@{$this->id}>"; } }