diff --git a/api/channel.go b/api/channel.go index 713f1a3..4d8f463 100644 --- a/api/channel.go +++ b/api/channel.go @@ -46,31 +46,24 @@ func (c *Client) CreateChannel( ) } -func (c *Client) MoveChannel( - guildID, channelID discord.Snowflake, position int) error { - - var param struct { - ID discord.Snowflake `json:"id"` - Pos int `json:"position"` - } - - param.ID = channelID - param.Pos = position +type MoveChannelData struct { + ID discord.Snowflake `json:"id"` + Position json.OptionInt `json:"position,omitempty"` +} +// MoveChannel modifies the position of channels in the guild. Requires +// MANAGE_CHANNELS. +func (c *Client) MoveChannel(guildID discord.Snowflake, datum []MoveChannelData) error { return c.FastRequest( "PATCH", EndpointGuilds+guildID.String()+"/channels", - httputil.WithJSONBody(c, param), + httputil.WithJSONBody(c, datum), ) } -func (c *Client) Channel( - channelID discord.Snowflake) (*discord.Channel, error) { - +func (c *Client) Channel(channelID discord.Snowflake) (*discord.Channel, error) { var channel *discord.Channel - - return channel, - c.RequestJSON(&channel, "GET", EndpointChannels+channelID.String()) + return channel, c.RequestJSON(&channel, "GET", EndpointChannels+channelID.String()) } type ModifyChannelData struct { @@ -111,45 +104,36 @@ func (c *Client) DeleteChannel(channelID discord.Snowflake) error { func (c *Client) EditChannelPermission( channelID discord.Snowflake, overwrite discord.Overwrite) error { - url := EndpointChannels + channelID.String() + "/permissions/" + - overwrite.ID.String() + url := EndpointChannels + channelID.String() + "/permissions/" + overwrite.ID.String() overwrite.ID = 0 return c.FastRequest("PUT", url, httputil.WithJSONBody(c, overwrite)) } -func (c *Client) DeleteChannelPermission( - channelID, overwriteID discord.Snowflake) error { - - return c.FastRequest("DELETE", EndpointChannels+channelID.String()+ - "/permissions/"+overwriteID.String()) +func (c *Client) DeleteChannelPermission(channelID, overwriteID discord.Snowflake) error { + return c.FastRequest("DELETE", + EndpointChannels+channelID.String()+"/permissions/"+overwriteID.String()) } // Typing posts a typing indicator to the channel. Undocumented, but the client // usually clears the typing indicator after 8-10 seconds (or after a message). func (c *Client) Typing(channelID discord.Snowflake) error { - return c.FastRequest("POST", - EndpointChannels+channelID.String()+"/typing") + return c.FastRequest("POST", EndpointChannels+channelID.String()+"/typing") } -func (c *Client) PinnedMessages( - channelID discord.Snowflake) ([]discord.Message, error) { - +func (c *Client) PinnedMessages(channelID discord.Snowflake) ([]discord.Message, error) { var pinned []discord.Message - return pinned, c.RequestJSON(&pinned, "GET", - EndpointChannels+channelID.String()+"/pins") + return pinned, c.RequestJSON(&pinned, "GET", EndpointChannels+channelID.String()+"/pins") } // PinMessage pins a message, which requires MANAGE_MESSAGES/ func (c *Client) PinMessage(channelID, messageID discord.Snowflake) error { - return c.FastRequest("PUT", - EndpointChannels+channelID.String()+"/pins/"+messageID.String()) + return c.FastRequest("PUT", EndpointChannels+channelID.String()+"/pins/"+messageID.String()) } // UnpinMessage also requires MANAGE_MESSAGES. func (c *Client) UnpinMessage(channelID, messageID discord.Snowflake) error { - return c.FastRequest("DELETE", - EndpointChannels+channelID.String()+"/pins/"+messageID.String()) + return c.FastRequest("DELETE", EndpointChannels+channelID.String()+"/pins/"+messageID.String()) } // AddRecipient adds a user to a group direct message. As accessToken is needed, @@ -179,13 +163,14 @@ func (c *Client) RemoveRecipient(channelID, userID discord.Snowflake) error { EndpointChannels+channelID.String()+"/recipients/"+userID.String()) } -// ACk is the read state of a channel. This is undocumented. +// Ack is the read state of a channel. This is undocumented. type Ack struct { Token string `json:"token"` } // Ack marks the read state of a channel. This is undocumented. The method will -// write to the ack variable passed in. +// write to the ack variable passed in. If this method is called asynchronously, +// then ack should be mutex guarded. func (c *Client) Ack(channelID, messageID discord.Snowflake, ack *Ack) error { return c.RequestJSON( ack, "POST", diff --git a/api/guild.go b/api/guild.go index e902468..b57def6 100644 --- a/api/guild.go +++ b/api/guild.go @@ -5,6 +5,7 @@ import ( "github.com/diamondburned/arikawa/discord" // for clarity "github.com/diamondburned/arikawa/utils/httputil" + "github.com/diamondburned/arikawa/utils/json" ) var EndpointGuilds = Endpoint + "guilds/" @@ -118,9 +119,8 @@ func (c *Client) LeaveGuild(guildID discord.Snowflake) error { // https://discordapp.com/developers/docs/resources/guild#modify-guild-json-params type ModifyGuildData struct { - Name string `json:"name,omitempty"` - Region string `json:"region,omitempty"` - Icon Image `json:"image,omitempty"` + Name string `json:"name,omitempty"` + Region json.OptionString `json:"region,omitempty"` // package d is just package discord Verification *discord.Verification `json:"verification_level,omitempty"` @@ -130,12 +130,17 @@ type ModifyGuildData struct { AFKChannelID *discord.Snowflake `json:"afk_channel_id,string,omitempty"` AFKTimeout *discord.Seconds `json:"afk_timeout,omitempty"` - OwnerID discord.Snowflake `json:"owner_id,string,omitempty"` + OwnerID discord.Snowflake `json:"owner_id,omitempty"` - Splash Image `json:"splash,omitempty"` - Banner Image `json:"banner,omitempty"` + Icon *Image `json:"icon,omitempty"` + Splash *Image `json:"splash,omitempty"` + Banner *Image `json:"banner,omitempty"` - SystemChannelID discord.Snowflake `json:"system_channel_id,string,omitempty"` + SystemChannelID *discord.Snowflake `json:"system_channel_id,omitempty"` + RulesChannelID *discord.Snowflake `json:"rules_channel_id,omitempty"` + PublicUpdatesChannelID *discord.Snowflake `json:"public_updates_channel_id,omitempty"` + + PreferredLocale json.OptionString `json:"preferred_locale,omitempty"` } func (c *Client) ModifyGuild( diff --git a/api/image.go b/api/image.go index 85a1b5a..c40a928 100644 --- a/api/image.go +++ b/api/image.go @@ -3,10 +3,10 @@ package api import ( "bytes" "encoding/base64" - "encoding/json" "fmt" "net/http" + "github.com/diamondburned/arikawa/utils/json" "github.com/pkg/errors" ) @@ -32,9 +32,6 @@ type Image struct { // Just raw content of the file. Content []byte - - // Utility fields, not used for encoding - MaxSize int // bytes } func DecodeImage(data []byte) (*Image, error) { @@ -61,9 +58,9 @@ func DecodeImage(data []byte) (*Image, error) { return &img, nil } -func (i Image) Validate() error { - if i.MaxSize > 0 && len(i.Content) > i.MaxSize { - return ErrImageTooLarge{len(i.Content), i.MaxSize} +func (i Image) Validate(maxSize int) error { + if maxSize > 0 && len(i.Content) > maxSize { + return ErrImageTooLarge{len(i.Content), maxSize} } switch i.ContentType { @@ -83,7 +80,7 @@ func (i Image) Encode() ([]byte, error) { i.ContentType = http.DetectContentType(i.Content[:max]) } - if err := i.Validate(); err != nil { + if err := i.Validate(0); err != nil { return nil, err } @@ -118,8 +115,9 @@ func (i *Image) UnmarshalJSON(v []byte) error { // Trim string v = bytes.Trim(v, `"`) + // Accept a nil image. if string(v) == "null" { - return ErrNoImage + return nil } img, err := DecodeImage(v) diff --git a/api/member.go b/api/member.go index 4ec4401..42be17e 100644 --- a/api/member.go +++ b/api/member.go @@ -3,6 +3,7 @@ package api import ( "github.com/diamondburned/arikawa/discord" "github.com/diamondburned/arikawa/utils/httputil" + "github.com/diamondburned/arikawa/utils/json" ) func (c *Client) Member( @@ -81,14 +82,14 @@ func (c *Client) MembersAfter( // AnyMemberData, all fields are optional. type AnyMemberData struct { - Nick string `json:"nick,omitempty"` - Mute bool `json:"mute,omitempty"` - Deaf bool `json:"deaf,omitempty"` + Nick json.OptionString `json:"nick,omitempty"` + Mute json.OptionBool `json:"mute,omitempty"` + Deaf json.OptionBool `json:"deaf,omitempty"` - Roles []discord.Snowflake `json:"roles,omitempty"` + Roles *[]discord.Snowflake `json:"roles,omitempty"` // Only for ModifyMember, requires MOVE_MEMBER - VoiceChannel discord.Snowflake `json:"channel_id,omitempty"` + VoiceChannel *discord.Snowflake `json:"channel_id,omitempty"` } // AddMember requires access(Token). @@ -96,8 +97,8 @@ func (c *Client) AddMember( guildID, userID discord.Snowflake, token string, data AnyMemberData) (*discord.Member, error) { - // VoiceChannel doesn't belong here - data.VoiceChannel = 0 + // VoiceChannel doesn't belong here. + data.VoiceChannel = nil var param struct { Token string `json:"access_token"` @@ -108,6 +109,7 @@ func (c *Client) AddMember( param.AnyMemberData = data var mem *discord.Member + return mem, c.RequestJSON( &mem, "PUT", EndpointGuilds+guildID.String()+"/members/"+userID.String(), @@ -127,9 +129,7 @@ func (c *Client) ModifyMember( // PruneCount returns the number of members that would be removed in a prune // operation. Requires KICK_MEMBERS. Days must be 1 or more, default 7. -func (c *Client) PruneCount( - guildID discord.Snowflake, days uint) (uint, error) { - +func (c *Client) PruneCount(guildID discord.Snowflake, days uint) (uint, error) { if days == 0 { days = 7 } @@ -153,9 +153,7 @@ func (c *Client) PruneCount( // Prune returns the number of members that is removed. Requires KICK_MEMBERS. // Days must be 1 or more, default 7. -func (c *Client) Prune( - guildID discord.Snowflake, days uint) (uint, error) { - +func (c *Client) Prune(guildID discord.Snowflake, days uint) (uint, error) { if days == 0 { days = 7 } @@ -191,9 +189,7 @@ func (c *Client) Bans(guildID discord.Snowflake) ([]discord.Ban, error) { EndpointGuilds+guildID.String()+"/bans") } -func (c *Client) GetBan( - guildID, userID discord.Snowflake) (*discord.Ban, error) { - +func (c *Client) GetBan(guildID, userID discord.Snowflake) (*discord.Ban, error) { var ban *discord.Ban return ban, c.RequestJSON(&ban, "GET", EndpointGuilds+guildID.String()+"/bans/"+userID.String()) @@ -201,9 +197,7 @@ func (c *Client) GetBan( // Ban requires the BAN_MEMBERS permission. Days is the days back for Discord // to delete the user's message, maximum 7 days. -func (c *Client) Ban( - guildID, userID discord.Snowflake, days uint, reason string) error { - +func (c *Client) Ban(guildID, userID discord.Snowflake, days uint, reason string) error { if days > 7 { days = 7 } @@ -223,8 +217,7 @@ func (c *Client) Ban( ) } -// Unban also requires BAN_MEMBERS. +// Unban requires BAN_MEMBERS. func (c *Client) Unban(guildID, userID discord.Snowflake) error { - return c.FastRequest("DELETE", - EndpointGuilds+guildID.String()+"/bans/"+userID.String()) + return c.FastRequest("DELETE", EndpointGuilds+guildID.String()+"/bans/"+userID.String()) } diff --git a/utils/json/raw.go b/utils/json/raw.go index 59385c3..b04114f 100644 --- a/utils/json/raw.go +++ b/utils/json/raw.go @@ -1,5 +1,13 @@ package json +type Marshaler interface { + MarshalJSON() ([]byte, error) +} + +type Unmarshaler interface { + UnmarshalJSON([]byte) error +} + // Raw is a raw encoded JSON value. It implements Marshaler and Unmarshaler and // can be used to delay JSON decoding or precompute a JSON encoding. It's taken // from encoding/json.