forked from pothtonswer/discordmuffin
Forum channels (#1246)
* feat: forums Initial implementation of forum channels REST API * fix: linter * feat: cosmetic changes Added periods in the end of all documentation comments * fix(ChannelFlagRequireTag): incorrect value Fix incorrect value of ChannelFlagRequireTag. * refactor(DefaultReaction): rename to ForumDefaultReaction Rename DefaultReaction to ForumDefaultReaction. * fix(Channel): use ForumDefaultReaction Use ForumDefaultReaction instead of DefaultReaction in DefaultReactionEmoji field. * fix: gofmt * feat: cosmetic changes * Change "GUILD_FORUM" to "forum" in comment to ForumTag * Fix spacing for documentation of embeds parameter in ForumThreadStartEmbeds * docs(ForumThreadStartComplex): align parameters Align documentation for parameters of ForumThreadStartComplex.
This commit is contained in:
parent
fea3d77574
commit
e57064892a
2 changed files with 176 additions and 22 deletions
94
restapi.go
94
restapi.go
|
@ -2496,6 +2496,100 @@ func (s *Session) ThreadStart(channelID, name string, typ ChannelType, archiveDu
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForumThreadStartComplex starts a new thread (creates a post) in a forum channel.
|
||||||
|
// channelID : Channel to create thread in.
|
||||||
|
// threadData : Parameters of the thread.
|
||||||
|
// messageData : Parameters of the starting message.
|
||||||
|
func (s *Session) ForumThreadStartComplex(channelID string, threadData *ThreadStart, messageData *MessageSend) (th *Channel, err error) {
|
||||||
|
endpoint := EndpointChannelThreads(channelID)
|
||||||
|
|
||||||
|
// TODO: Remove this when compatibility is not required.
|
||||||
|
if messageData.Embed != nil {
|
||||||
|
if messageData.Embeds == nil {
|
||||||
|
messageData.Embeds = []*MessageEmbed{messageData.Embed}
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("cannot specify both Embed and Embeds")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, embed := range messageData.Embeds {
|
||||||
|
if embed.Type == "" {
|
||||||
|
embed.Type = "rich"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove this when compatibility is not required.
|
||||||
|
files := messageData.Files
|
||||||
|
if messageData.File != nil {
|
||||||
|
if files == nil {
|
||||||
|
files = []*File{messageData.File}
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("cannot specify both File and Files")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data := struct {
|
||||||
|
*ThreadStart
|
||||||
|
Message *MessageSend `json:"message"`
|
||||||
|
}{ThreadStart: threadData, Message: messageData}
|
||||||
|
|
||||||
|
var response []byte
|
||||||
|
if len(files) > 0 {
|
||||||
|
contentType, body, encodeErr := MultipartBodyWithJSON(data, files)
|
||||||
|
if encodeErr != nil {
|
||||||
|
return th, encodeErr
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err = s.request("POST", endpoint, contentType, body, endpoint, 0)
|
||||||
|
} else {
|
||||||
|
response, err = s.RequestWithBucketID("POST", endpoint, data, endpoint)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = unmarshal(response, &th)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForumThreadStart starts a new thread (post) in a forum channel.
|
||||||
|
// channelID : Channel to create thread in.
|
||||||
|
// name : Name of the thread.
|
||||||
|
// archiveDuration : Auto archive duration.
|
||||||
|
// content : Content of the starting message.
|
||||||
|
func (s *Session) ForumThreadStart(channelID, name string, archiveDuration int, content string) (th *Channel, err error) {
|
||||||
|
return s.ForumThreadStartComplex(channelID, &ThreadStart{
|
||||||
|
Name: name,
|
||||||
|
AutoArchiveDuration: archiveDuration,
|
||||||
|
}, &MessageSend{Content: content})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForumThreadStartEmbed starts a new thread (post) in a forum channel.
|
||||||
|
// channelID : Channel to create thread in.
|
||||||
|
// name : Name of the thread.
|
||||||
|
// archiveDuration : Auto archive duration.
|
||||||
|
// embed : Embed data of the starting message.
|
||||||
|
func (s *Session) ForumThreadStartEmbed(channelID, name string, archiveDuration int, embed *MessageEmbed) (th *Channel, err error) {
|
||||||
|
return s.ForumThreadStartComplex(channelID, &ThreadStart{
|
||||||
|
Name: name,
|
||||||
|
AutoArchiveDuration: archiveDuration,
|
||||||
|
}, &MessageSend{Embeds: []*MessageEmbed{embed}})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForumThreadStartEmbeds starts a new thread (post) in a forum channel.
|
||||||
|
// channelID : Channel to create thread in.
|
||||||
|
// name : Name of the thread.
|
||||||
|
// archiveDuration : Auto archive duration.
|
||||||
|
// embeds : Embeds data of the starting message.
|
||||||
|
func (s *Session) ForumThreadStartEmbeds(channelID, name string, archiveDuration int, embeds []*MessageEmbed) (th *Channel, err error) {
|
||||||
|
return s.ForumThreadStartComplex(channelID, &ThreadStart{
|
||||||
|
Name: name,
|
||||||
|
AutoArchiveDuration: archiveDuration,
|
||||||
|
}, &MessageSend{Embeds: embeds})
|
||||||
|
}
|
||||||
|
|
||||||
// ThreadJoin adds current user to a thread
|
// ThreadJoin adds current user to a thread
|
||||||
func (s *Session) ThreadJoin(id string) error {
|
func (s *Session) ThreadJoin(id string) error {
|
||||||
endpoint := EndpointThreadMember(id, "@me")
|
endpoint := EndpointThreadMember(id, "@me")
|
||||||
|
|
104
structs.go
104
structs.go
|
@ -254,6 +254,20 @@ const (
|
||||||
ChannelTypeGuildPublicThread ChannelType = 11
|
ChannelTypeGuildPublicThread ChannelType = 11
|
||||||
ChannelTypeGuildPrivateThread ChannelType = 12
|
ChannelTypeGuildPrivateThread ChannelType = 12
|
||||||
ChannelTypeGuildStageVoice ChannelType = 13
|
ChannelTypeGuildStageVoice ChannelType = 13
|
||||||
|
ChannelTypeGuildForum ChannelType = 15
|
||||||
|
)
|
||||||
|
|
||||||
|
// ChannelFlags represent flags of a channel/thread.
|
||||||
|
type ChannelFlags int
|
||||||
|
|
||||||
|
// Block containing known ChannelFlags values.
|
||||||
|
const (
|
||||||
|
// ChannelFlagPinned indicates whether the thread is pinned in the forum channel.
|
||||||
|
// NOTE: forum threads only.
|
||||||
|
ChannelFlagPinned ChannelFlags = 1 << 1
|
||||||
|
// ChannelFlagRequireTag indicates whether a tag is required to be specified when creating a thread.
|
||||||
|
// NOTE: forum channels only.
|
||||||
|
ChannelFlagRequireTag ChannelFlags = 1 << 4
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Channel holds all data related to an individual Discord channel.
|
// A Channel holds all data related to an individual Discord channel.
|
||||||
|
@ -332,6 +346,18 @@ type Channel struct {
|
||||||
|
|
||||||
// All thread members. State channels only.
|
// All thread members. State channels only.
|
||||||
Members []*ThreadMember `json:"-"`
|
Members []*ThreadMember `json:"-"`
|
||||||
|
|
||||||
|
// Channel flags.
|
||||||
|
Flags ChannelFlags `json:"flags"`
|
||||||
|
|
||||||
|
// The set of tags that can be used in a forum channel.
|
||||||
|
AvailableTags []ForumTag `json:"available_tags"`
|
||||||
|
|
||||||
|
// The IDs of the set of tags that have been applied to a thread in a forum channel.
|
||||||
|
AppliedTags []string `json:"applied_tags"`
|
||||||
|
|
||||||
|
// Emoji to use as the default reaction to a forum post.
|
||||||
|
DefaultReactionEmoji ForumDefaultReaction `json:"default_reaction_emoji"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mention returns a string which mentions the channel
|
// Mention returns a string which mentions the channel
|
||||||
|
@ -355,6 +381,7 @@ type ChannelEdit struct {
|
||||||
PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites,omitempty"`
|
PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites,omitempty"`
|
||||||
ParentID string `json:"parent_id,omitempty"`
|
ParentID string `json:"parent_id,omitempty"`
|
||||||
RateLimitPerUser *int `json:"rate_limit_per_user,omitempty"`
|
RateLimitPerUser *int `json:"rate_limit_per_user,omitempty"`
|
||||||
|
Flags *ChannelFlags `json:"flags,omitempty"`
|
||||||
|
|
||||||
// NOTE: threads only
|
// NOTE: threads only
|
||||||
|
|
||||||
|
@ -362,6 +389,14 @@ type ChannelEdit struct {
|
||||||
AutoArchiveDuration int `json:"auto_archive_duration,omitempty"`
|
AutoArchiveDuration int `json:"auto_archive_duration,omitempty"`
|
||||||
Locked *bool `json:"locked,omitempty"`
|
Locked *bool `json:"locked,omitempty"`
|
||||||
Invitable *bool `json:"invitable,omitempty"`
|
Invitable *bool `json:"invitable,omitempty"`
|
||||||
|
|
||||||
|
// NOTE: forum channels only
|
||||||
|
|
||||||
|
AvailableTags *[]ForumTag `json:"available_tags,omitempty"`
|
||||||
|
DefaultReactionEmoji *ForumDefaultReaction `json:"default_reaction_emoji,omitempty"`
|
||||||
|
|
||||||
|
// NOTE: forum threads only
|
||||||
|
AppliedTags *[]string `json:"applied_tags,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// A ChannelFollow holds data returned after following a news channel
|
// A ChannelFollow holds data returned after following a news channel
|
||||||
|
@ -395,6 +430,9 @@ type ThreadStart struct {
|
||||||
Type ChannelType `json:"type,omitempty"`
|
Type ChannelType `json:"type,omitempty"`
|
||||||
Invitable bool `json:"invitable"`
|
Invitable bool `json:"invitable"`
|
||||||
RateLimitPerUser int `json:"rate_limit_per_user,omitempty"`
|
RateLimitPerUser int `json:"rate_limit_per_user,omitempty"`
|
||||||
|
|
||||||
|
// NOTE: forum threads only
|
||||||
|
AppliedTags []string `json:"applied_tags,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ThreadMetadata contains a number of thread-specific channel fields that are not needed by other channel types.
|
// ThreadMetadata contains a number of thread-specific channel fields that are not needed by other channel types.
|
||||||
|
@ -438,6 +476,24 @@ type AddedThreadMember struct {
|
||||||
Presence *Presence `json:"presence"`
|
Presence *Presence `json:"presence"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForumDefaultReaction specifies emoji to use as the default reaction to a forum post.
|
||||||
|
// NOTE: Exactly one of EmojiID and EmojiName must be set.
|
||||||
|
type ForumDefaultReaction struct {
|
||||||
|
// The id of a guild's custom emoji.
|
||||||
|
EmojiID string `json:"emoji_id,omitempty"`
|
||||||
|
// The unicode character of the emoji.
|
||||||
|
EmojiName string `json:"emoji_name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForumTag represents a tag that is able to be applied to a thread in a forum channel.
|
||||||
|
type ForumTag struct {
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Moderated bool `json:"moderated"`
|
||||||
|
EmojiID string `json:"emoji_id,omitempty"`
|
||||||
|
EmojiName string `json:"emoji_name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Emoji struct holds data related to Emoji's
|
// Emoji struct holds data related to Emoji's
|
||||||
type Emoji struct {
|
type Emoji struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
|
@ -2074,6 +2130,7 @@ const (
|
||||||
ErrCodeUnknownGuildWelcomeScreen = 10069
|
ErrCodeUnknownGuildWelcomeScreen = 10069
|
||||||
ErrCodeUnknownGuildScheduledEvent = 10070
|
ErrCodeUnknownGuildScheduledEvent = 10070
|
||||||
ErrCodeUnknownGuildScheduledEventUser = 10071
|
ErrCodeUnknownGuildScheduledEventUser = 10071
|
||||||
|
ErrUnknownTag = 10087
|
||||||
|
|
||||||
ErrCodeBotsCannotUseEndpoint = 20001
|
ErrCodeBotsCannotUseEndpoint = 20001
|
||||||
ErrCodeOnlyBotsCanUseEndpoint = 20002
|
ErrCodeOnlyBotsCanUseEndpoint = 20002
|
||||||
|
@ -2087,28 +2144,30 @@ const (
|
||||||
ErrCodeStageTopicContainsNotAllowedWordsForPublicStages = 20031
|
ErrCodeStageTopicContainsNotAllowedWordsForPublicStages = 20031
|
||||||
ErrCodeGuildPremiumSubscriptionLevelTooLow = 20035
|
ErrCodeGuildPremiumSubscriptionLevelTooLow = 20035
|
||||||
|
|
||||||
ErrCodeMaximumGuildsReached = 30001
|
ErrCodeMaximumGuildsReached = 30001
|
||||||
ErrCodeMaximumPinsReached = 30003
|
ErrCodeMaximumPinsReached = 30003
|
||||||
ErrCodeMaximumNumberOfRecipientsReached = 30004
|
ErrCodeMaximumNumberOfRecipientsReached = 30004
|
||||||
ErrCodeMaximumGuildRolesReached = 30005
|
ErrCodeMaximumGuildRolesReached = 30005
|
||||||
ErrCodeMaximumNumberOfWebhooksReached = 30007
|
ErrCodeMaximumNumberOfWebhooksReached = 30007
|
||||||
ErrCodeMaximumNumberOfEmojisReached = 30008
|
ErrCodeMaximumNumberOfEmojisReached = 30008
|
||||||
ErrCodeTooManyReactions = 30010
|
ErrCodeTooManyReactions = 30010
|
||||||
ErrCodeMaximumNumberOfGuildChannelsReached = 30013
|
ErrCodeMaximumNumberOfGuildChannelsReached = 30013
|
||||||
ErrCodeMaximumNumberOfAttachmentsInAMessageReached = 30015
|
ErrCodeMaximumNumberOfAttachmentsInAMessageReached = 30015
|
||||||
ErrCodeMaximumNumberOfInvitesReached = 30016
|
ErrCodeMaximumNumberOfInvitesReached = 30016
|
||||||
ErrCodeMaximumNumberOfAnimatedEmojisReached = 30018
|
ErrCodeMaximumNumberOfAnimatedEmojisReached = 30018
|
||||||
ErrCodeMaximumNumberOfServerMembersReached = 30019
|
ErrCodeMaximumNumberOfServerMembersReached = 30019
|
||||||
ErrCodeMaximumNumberOfGuildDiscoverySubcategoriesReached = 30030
|
ErrCodeMaximumNumberOfGuildDiscoverySubcategoriesReached = 30030
|
||||||
ErrCodeGuildAlreadyHasATemplate = 30031
|
ErrCodeGuildAlreadyHasATemplate = 30031
|
||||||
ErrCodeMaximumNumberOfThreadParticipantsReached = 30033
|
ErrCodeMaximumNumberOfThreadParticipantsReached = 30033
|
||||||
ErrCodeMaximumNumberOfBansForNonGuildMembersHaveBeenExceeded = 30035
|
ErrCodeMaximumNumberOfBansForNonGuildMembersHaveBeenExceeded = 30035
|
||||||
ErrCodeMaximumNumberOfBansFetchesHasBeenReached = 30037
|
ErrCodeMaximumNumberOfBansFetchesHasBeenReached = 30037
|
||||||
ErrCodeMaximumNumberOfUncompletedGuildScheduledEventsReached = 30038
|
ErrCodeMaximumNumberOfUncompletedGuildScheduledEventsReached = 30038
|
||||||
ErrCodeMaximumNumberOfStickersReached = 30039
|
ErrCodeMaximumNumberOfStickersReached = 30039
|
||||||
ErrCodeMaximumNumberOfPruneRequestsHasBeenReached = 30040
|
ErrCodeMaximumNumberOfPruneRequestsHasBeenReached = 30040
|
||||||
ErrCodeMaximumNumberOfGuildWidgetSettingsUpdatesHasBeenReached = 30042
|
ErrCodeMaximumNumberOfGuildWidgetSettingsUpdatesHasBeenReached = 30042
|
||||||
ErrCodeMaximumNumberOfEditsToMessagesOlderThanOneHourReached = 30046
|
ErrCodeMaximumNumberOfEditsToMessagesOlderThanOneHourReached = 30046
|
||||||
|
ErrCodeMaximumNumberOfPinnedThreadsInForumChannelHasBeenReached = 30047
|
||||||
|
ErrCodeMaximumNumberOfTagsInForumChannelHasBeenReached = 30048
|
||||||
|
|
||||||
ErrCodeUnauthorized = 40001
|
ErrCodeUnauthorized = 40001
|
||||||
ErrCodeActionRequiredVerifiedAccount = 40002
|
ErrCodeActionRequiredVerifiedAccount = 40002
|
||||||
|
@ -2121,6 +2180,7 @@ const (
|
||||||
ErrCodeMessageAlreadyCrossposted = 40033
|
ErrCodeMessageAlreadyCrossposted = 40033
|
||||||
ErrCodeAnApplicationWithThatNameAlreadyExists = 40041
|
ErrCodeAnApplicationWithThatNameAlreadyExists = 40041
|
||||||
ErrCodeInteractionHasAlreadyBeenAcknowledged = 40060
|
ErrCodeInteractionHasAlreadyBeenAcknowledged = 40060
|
||||||
|
ErrCodeTagNamesMustBeUnique = 40061
|
||||||
|
|
||||||
ErrCodeMissingAccess = 50001
|
ErrCodeMissingAccess = 50001
|
||||||
ErrCodeInvalidAccountType = 50002
|
ErrCodeInvalidAccountType = 50002
|
||||||
|
|
Loading…
Reference in a new issue