rubycord-webhooks 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f69acce055f71571b168e5b31c33c9f3cb9fd3b7e66fd98209c5dae8880996f4
4
+ data.tar.gz: 65445fcacd5aef759933a84c9826e800554752ca54a84e7493269eeb750b1d76
5
+ SHA512:
6
+ metadata.gz: 20e590c6fe62a248bce94dfa4741d0156c3e9f6329ae9655b1972090e8567f4366dc1476f4ce0f3d6649077c9c9118b257baec77cbdc91774efabc68d6f81638
7
+ data.tar.gz: 9755b4c269c647d1d03a5d9b722d00c3fa6ac4514c9992bad9862376161a2f62d2226ff35b3e6881eee1c7208cbcd3396da0949014efc86e838d7f39f20049fa
@@ -0,0 +1,100 @@
1
+ require "rubycord/webhooks/embeds"
2
+
3
+ module Rubycord::Webhooks
4
+ # A class that acts as a builder for a webhook message object.
5
+ class Builder
6
+ def initialize(content: "", username: nil, avatar_url: nil, tts: false, file: nil, embeds: [], allowed_mentions: nil)
7
+ @content = content
8
+ @username = username
9
+ @avatar_url = avatar_url
10
+ @tts = tts
11
+ @file = file
12
+ @embeds = embeds
13
+ @allowed_mentions = allowed_mentions
14
+ end
15
+
16
+ # The content of the message. May be 2000 characters long at most.
17
+ # @return [String] the content of the message.
18
+ attr_accessor :content
19
+
20
+ # The username the webhook will display as. If this is not set, the default username set in the webhook's settings
21
+ # will be used instead.
22
+ # @return [String] the username.
23
+ attr_accessor :username
24
+
25
+ # The URL of an image file to be used as an avatar. If this is not set, the default avatar from the webhook's
26
+ # settings will be used instead.
27
+ # @return [String] the avatar URL.
28
+ attr_accessor :avatar_url
29
+
30
+ # Whether this message should use TTS or not. By default, it doesn't.
31
+ # @return [true, false] the TTS status.
32
+ attr_accessor :tts
33
+
34
+ # Sets a file to be sent together with the message. Mutually exclusive with embeds; a webhook message can contain
35
+ # either a file to be sent or an embed.
36
+ # @param file [File] A file to be sent.
37
+ def file=(file)
38
+ raise ArgumentError, "Embeds and files are mutually exclusive!" unless @embeds.empty?
39
+
40
+ @file = file
41
+ end
42
+
43
+ # Adds an embed to this message.
44
+ # @param embed [Embed] The embed to add.
45
+ def <<(embed)
46
+ raise ArgumentError, "Embeds and files are mutually exclusive!" if @file
47
+
48
+ @embeds << embed
49
+ end
50
+
51
+ # Convenience method to add an embed using a block-style builder pattern
52
+ # @example Add an embed to a message
53
+ # builder.add_embed do |embed|
54
+ # embed.title = 'Testing'
55
+ # embed.image = Rubycord::Webhooks::EmbedImage.new(url: 'https://i.imgur.com/PcMltU7.jpg')
56
+ # end
57
+ # @param embed [Embed, nil] The embed to start the building process with, or nil if one should be created anew.
58
+ # @return [Embed] The created embed.
59
+ def add_embed(embed = nil)
60
+ embed ||= Embed.new
61
+ yield(embed)
62
+ self << embed
63
+ embed
64
+ end
65
+
66
+ # @return [File, nil] the file attached to this message.
67
+ attr_reader :file
68
+
69
+ # @return [Array<Embed>] the embeds attached to this message.
70
+ attr_reader :embeds
71
+
72
+ # @return [Rubycord::AllowedMentions, Hash] Mentions that are allowed to ping in this message.
73
+ # @see https://discord.com/developers/docs/resources/channel#allowed-mentions-object
74
+ attr_accessor :allowed_mentions
75
+
76
+ # @return [Hash] a hash representation of the created message, for JSON format.
77
+ def to_json_hash
78
+ {
79
+ content: @content,
80
+ username: @username,
81
+ avatar_url: @avatar_url,
82
+ tts: @tts,
83
+ embeds: @embeds.map(&:to_hash),
84
+ allowed_mentions: @allowed_mentions&.to_hash
85
+ }
86
+ end
87
+
88
+ # @return [Hash] a hash representation of the created message, for multipart format.
89
+ def to_multipart_hash
90
+ {
91
+ content: @content,
92
+ username: @username,
93
+ avatar_url: @avatar_url,
94
+ tts: @tts,
95
+ file: @file,
96
+ allowed_mentions: @allowed_mentions&.to_hash
97
+ }
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,132 @@
1
+ require "rest-client"
2
+ require "json"
3
+
4
+ require "rubycord/webhooks/builder"
5
+
6
+ module Rubycord::Webhooks
7
+ # A client for a particular webhook added to a Discord channel.
8
+ class Client
9
+ # Create a new webhook
10
+ # @param url [String] The URL to post messages to.
11
+ # @param id [Integer] The webhook's ID. Will only be used if `url` is not
12
+ # set.
13
+ # @param token [String] The webhook's authorisation token. Will only be used
14
+ # if `url` is not set.
15
+ def initialize(url: nil, id: nil, token: nil)
16
+ @url = url || generate_url(id, token)
17
+ end
18
+
19
+ # Executes the webhook this client points to with the given data.
20
+ # @param builder [Builder, nil] The builder to start out with, or nil if one should be created anew.
21
+ # @param wait [true, false] Whether Discord should wait for the message to be successfully received by clients, or
22
+ # whether it should return immediately after sending the message.
23
+ # @yield [builder] Gives the builder to the block to add additional steps, or to do the entire building process.
24
+ # @yieldparam builder [Builder] The builder given as a parameter which is used as the initial step to start from.
25
+ # @example Execute the webhook with an already existing builder
26
+ # builder = Rubycord::Webhooks::Builder.new # ...
27
+ # client.execute(builder)
28
+ # @example Execute the webhook by building a new message
29
+ # client.execute do |builder|
30
+ # builder.content = 'Testing'
31
+ # builder.username = 'rubycord'
32
+ # builder.add_embed do |embed|
33
+ # embed.timestamp = Time.now
34
+ # embed.title = 'Testing'
35
+ # embed.image = Rubycord::Webhooks::EmbedImage.new(url: 'https://i.imgur.com/PcMltU7.jpg')
36
+ # end
37
+ # end
38
+ # @return [RestClient::Response] the response returned by Discord.
39
+ def execute(builder = nil, wait = false, components = nil)
40
+ raise TypeError, "builder needs to be nil or like a Rubycord::Webhooks::Builder!" if
41
+ !(builder.respond_to?(:file) && builder.respond_to?(:to_multipart_hash)) && !builder.respond_to?(:to_json_hash) && !builder.nil?
42
+
43
+ builder ||= Builder.new
44
+ view = View.new
45
+
46
+ yield(builder, view) if block_given?
47
+
48
+ components ||= view
49
+
50
+ if builder.file
51
+ post_multipart(builder, components, wait)
52
+ else
53
+ post_json(builder, components, wait)
54
+ end
55
+ end
56
+
57
+ # Modify this webhook's properties.
58
+ # @param name [String, nil] The default name.
59
+ # @param avatar [String, #read, nil] The new avatar, in base64-encoded JPG format.
60
+ # @param channel_id [String, Integer, nil] The channel to move the webhook to.
61
+ # @return [RestClient::Response] the response returned by Discord.
62
+ def modify(name: nil, avatar: nil, channel_id: nil)
63
+ RestClient.patch(@url, {name: name, avatar: avatarise(avatar), channel_id: channel_id}.compact.to_json, content_type: :json)
64
+ end
65
+
66
+ # Delete this webhook.
67
+ # @param reason [String, nil] The reason this webhook was deleted.
68
+ # @return [RestClient::Response] the response returned by Discord.
69
+ # @note This is permanent and cannot be undone.
70
+ def delete(reason: nil)
71
+ RestClient.delete(@url, "X-Audit-Log-Reason": reason)
72
+ end
73
+
74
+ # Edit a message from this webhook.
75
+ # @param message_id [String, Integer] The ID of the message to edit.
76
+ # @param builder [Builder, nil] The builder to start out with, or nil if one should be created anew.
77
+ # @param content [String] The message content.
78
+ # @param embeds [Array<Embed, Hash>]
79
+ # @param allowed_mentions [Hash]
80
+ # @return [RestClient::Response] the response returned by Discord.
81
+ # @example Edit message content
82
+ # client.edit_message(message_id, content: 'goodbye world!')
83
+ # @example Edit a message via builder
84
+ # client.edit_message(message_id) do |builder|
85
+ # builder.add_embed do |e|
86
+ # e.description = 'Hello World!'
87
+ # end
88
+ # end
89
+ # @note Not all builder options are available when editing.
90
+ def edit_message(message_id, builder: nil, content: nil, embeds: nil, allowed_mentions: nil)
91
+ builder ||= Builder.new
92
+
93
+ yield builder if block_given?
94
+
95
+ data = builder.to_json_hash.merge({content: content, embeds: embeds, allowed_mentions: allowed_mentions}.compact)
96
+ RestClient.patch("#{@url}/messages/#{message_id}", data.compact.to_json, content_type: :json)
97
+ end
98
+
99
+ # Delete a message created by this webhook.
100
+ # @param message_id [String, Integer] The ID of the message to delete.
101
+ # @return [RestClient::Response] the response returned by Discord.
102
+ def delete_message(message_id)
103
+ RestClient.delete("#{@url}/messages/#{message_id}")
104
+ end
105
+
106
+ private
107
+
108
+ # Convert an avatar to API ready data.
109
+ # @param avatar [String, #read] Avatar data.
110
+ def avatarise(avatar)
111
+ if avatar.respond_to? :read
112
+ "data:image/jpg;base64,#{Base64.strict_encode64(avatar.read)}"
113
+ else
114
+ avatar
115
+ end
116
+ end
117
+
118
+ def post_json(builder, components, wait)
119
+ data = builder.to_json_hash.merge({components: components.to_a})
120
+ RestClient.post(@url + (wait ? "?wait=true" : ""), data.to_json, content_type: :json)
121
+ end
122
+
123
+ def post_multipart(builder, components, wait)
124
+ data = builder.to_multipart_hash.merge({components: components.to_a})
125
+ RestClient.post(@url + (wait ? "?wait=true" : ""), data)
126
+ end
127
+
128
+ def generate_url(id, token)
129
+ "https://discord.com/api/v9/webhooks/#{id}/#{token}"
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,248 @@
1
+ module Rubycord::Webhooks
2
+ # An embed is a multipart-style attachment to a webhook message that can have a variety of different purposes and
3
+ # appearances.
4
+ class Embed
5
+ def initialize(title: nil, description: nil, url: nil, timestamp: nil, colour: nil, color: nil, footer: nil,
6
+ image: nil, thumbnail: nil, video: nil, provider: nil, author: nil, fields: [])
7
+ @title = title
8
+ @description = description
9
+ @url = url
10
+ @timestamp = timestamp
11
+ self.colour = colour || color
12
+ @footer = footer
13
+ @image = image
14
+ @thumbnail = thumbnail
15
+ @video = video
16
+ @provider = provider
17
+ @author = author
18
+ @fields = fields
19
+ end
20
+
21
+ # @return [String, nil] title of the embed that will be displayed above everything else.
22
+ attr_accessor :title
23
+
24
+ # @return [String, nil] description for this embed
25
+ attr_accessor :description
26
+
27
+ # @return [String, nil] URL the title should point to
28
+ attr_accessor :url
29
+
30
+ # @return [Time, nil] timestamp for this embed. Will be displayed just below the title.
31
+ attr_accessor :timestamp
32
+
33
+ # @return [Integer, nil] the colour of the bar to the side, in decimal form
34
+ attr_reader :colour
35
+ alias_method :color, :colour
36
+
37
+ # Sets the colour of the bar to the side of the embed to something new.
38
+ # @param value [String, Integer, {Integer, Integer, Integer}, #to_i, nil] The colour in decimal, hexadecimal, R/G/B decimal, or nil to clear the embeds colour
39
+ # form.
40
+ def colour=(value)
41
+ if value.nil?
42
+ @colour = nil
43
+ elsif value.is_a? Integer
44
+ raise ArgumentError, "Embed colour must be 24-bit!" if value >= 16_777_216
45
+
46
+ @colour = value
47
+ elsif value.is_a? String
48
+ self.colour = value.delete("#").to_i(16)
49
+ elsif value.is_a? Array
50
+ raise ArgumentError, "Colour tuple must have three values!" if value.length != 3
51
+
52
+ self.colour = (value[0] << 16) | (value[1] << 8) | value[2]
53
+ else
54
+ self.colour = value.to_i
55
+ end
56
+ end
57
+
58
+ alias_method :color=, :colour=
59
+
60
+ # @example Add a footer to an embed
61
+ # embed.footer = Rubycord::Webhooks::EmbedFooter.new(text: 'Hello', icon_url: 'https://i.imgur.com/j69wMDu.jpg')
62
+ # @return [EmbedFooter, nil] footer for this embed
63
+ attr_accessor :footer
64
+
65
+ # @see EmbedImage
66
+ # @example Add a image to an embed
67
+ # embed.image = Rubycord::Webhooks::EmbedImage.new(url: 'https://i.imgur.com/PcMltU7.jpg')
68
+ # @return [EmbedImage, nil] image for this embed
69
+ attr_accessor :image
70
+
71
+ # @see EmbedThumbnail
72
+ # @example Add a thumbnail to an embed
73
+ # embed.thumbnail = Rubycord::Webhooks::EmbedThumbnail.new(url: 'https://i.imgur.com/xTG3a1I.jpg')
74
+ # @return [EmbedThumbnail, nil] thumbnail for this embed
75
+ attr_accessor :thumbnail
76
+
77
+ # @see EmbedAuthor
78
+ # @example Add a author to an embed
79
+ # embed.author = Rubycord::Webhooks::EmbedAuthor.new(name: 'meew0', url: 'https://github.com/meew0', icon_url: 'https://avatars2.githubusercontent.com/u/3662915?v=3&s=466')
80
+ # @return [EmbedAuthor, nil] author for this embed
81
+ attr_accessor :author
82
+
83
+ # Add a field object to this embed.
84
+ # @param field [EmbedField] The field to add.
85
+ def <<(field)
86
+ @fields << field
87
+ end
88
+
89
+ # Convenience method to add a field to the embed without having to create one manually.
90
+ # @see EmbedField
91
+ # @example Add a field to an embed, conveniently
92
+ # embed.add_field(name: 'A field', value: "The field's content")
93
+ # @param name [String] The field's name
94
+ # @param value [String] The field's value
95
+ # @param inline [true, false] Whether the field should be inline
96
+ def add_field(name: nil, value: nil, inline: nil)
97
+ self << EmbedField.new(name: name, value: value, inline: inline)
98
+ end
99
+
100
+ # @return [Array<EmbedField>] the fields attached to this embed.
101
+ attr_accessor :fields
102
+
103
+ # @return [Hash] a hash representation of this embed, to be converted to JSON.
104
+ def to_hash
105
+ {
106
+ title: @title,
107
+ description: @description,
108
+ url: @url,
109
+ timestamp: @timestamp&.utc&.iso8601,
110
+ color: @colour,
111
+ footer: @footer&.to_hash,
112
+ image: @image&.to_hash,
113
+ thumbnail: @thumbnail&.to_hash,
114
+ video: @video&.to_hash,
115
+ provider: @provider&.to_hash,
116
+ author: @author&.to_hash,
117
+ fields: @fields.map(&:to_hash)
118
+ }
119
+ end
120
+ end
121
+
122
+ # An embed's footer will be displayed at the very bottom of an embed, together with the timestamp. An icon URL can be
123
+ # set together with some text to be displayed.
124
+ class EmbedFooter
125
+ # @return [String, nil] text to be displayed in the footer
126
+ attr_accessor :text
127
+
128
+ # @return [String, nil] URL to an icon to be showed alongside the text
129
+ attr_accessor :icon_url
130
+
131
+ # Creates a new footer object.
132
+ # @param text [String, nil] The text to be displayed in the footer.
133
+ # @param icon_url [String, nil] The URL to an icon to be showed alongside the text.
134
+ def initialize(text: nil, icon_url: nil)
135
+ @text = text
136
+ @icon_url = icon_url
137
+ end
138
+
139
+ # @return [Hash] a hash representation of this embed footer, to be converted to JSON.
140
+ def to_hash
141
+ {
142
+ text: @text,
143
+ icon_url: @icon_url
144
+ }
145
+ end
146
+ end
147
+
148
+ # An embed's image will be displayed at the bottom, in large format. It will replace a footer icon URL if one is set.
149
+ class EmbedImage
150
+ # @return [String, nil] URL of the image
151
+ attr_accessor :url
152
+
153
+ # Creates a new image object.
154
+ # @param url [String, nil] The URL of the image.
155
+ def initialize(url: nil)
156
+ @url = url
157
+ end
158
+
159
+ # @return [Hash] a hash representation of this embed image, to be converted to JSON.
160
+ def to_hash
161
+ {
162
+ url: @url
163
+ }
164
+ end
165
+ end
166
+
167
+ # An embed's thumbnail will be displayed at the right of the message, next to the description and fields. When clicked
168
+ # it will point to the embed URL.
169
+ class EmbedThumbnail
170
+ # @return [String, nil] URL of the thumbnail
171
+ attr_accessor :url
172
+
173
+ # Creates a new thumbnail object.
174
+ # @param url [String, nil] The URL of the thumbnail.
175
+ def initialize(url: nil)
176
+ @url = url
177
+ end
178
+
179
+ # @return [Hash] a hash representation of this embed thumbnail, to be converted to JSON.
180
+ def to_hash
181
+ {
182
+ url: @url
183
+ }
184
+ end
185
+ end
186
+
187
+ # An embed's author will be shown at the top to indicate who "authored" the particular event the webhook was sent for.
188
+ class EmbedAuthor
189
+ # @return [String, nil] name of the author
190
+ attr_accessor :name
191
+
192
+ # @return [String, nil] URL the name should link to
193
+ attr_accessor :url
194
+
195
+ # @return [String, nil] URL of the icon to be displayed next to the author
196
+ attr_accessor :icon_url
197
+
198
+ # Creates a new author object.
199
+ # @param name [String, nil] The name of the author.
200
+ # @param url [String, nil] The URL the name should link to.
201
+ # @param icon_url [String, nil] The URL of the icon to be displayed next to the author.
202
+ def initialize(name: nil, url: nil, icon_url: nil)
203
+ @name = name
204
+ @url = url
205
+ @icon_url = icon_url
206
+ end
207
+
208
+ # @return [Hash] a hash representation of this embed author, to be converted to JSON.
209
+ def to_hash
210
+ {
211
+ name: @name,
212
+ url: @url,
213
+ icon_url: @icon_url
214
+ }
215
+ end
216
+ end
217
+
218
+ # A field is a small block of text with a header that can be relatively freely layouted with other fields.
219
+ class EmbedField
220
+ # @return [String, nil] name of the field, displayed in bold at the top of the field.
221
+ attr_accessor :name
222
+
223
+ # @return [String, nil] value of the field, displayed in normal text below the name.
224
+ attr_accessor :value
225
+
226
+ # @return [true, false] whether the field should be displayed inline with other fields.
227
+ attr_accessor :inline
228
+
229
+ # Creates a new field object.
230
+ # @param name [String, nil] The name of the field, displayed in bold at the top of the field.
231
+ # @param value [String, nil] The value of the field, displayed in normal text below the name.
232
+ # @param inline [true, false] Whether the field should be displayed inline with other fields.
233
+ def initialize(name: nil, value: nil, inline: false)
234
+ @name = name
235
+ @value = value
236
+ @inline = inline
237
+ end
238
+
239
+ # @return [Hash] a hash representation of this embed field, to be converted to JSON.
240
+ def to_hash
241
+ {
242
+ name: @name,
243
+ value: @value,
244
+ inline: @inline
245
+ }
246
+ end
247
+ end
248
+ end
@@ -0,0 +1,78 @@
1
+ # Modal component builder.
2
+ class Rubycord::Webhooks::Modal
3
+ # A mapping of names to types of components usable in a modal.
4
+ COMPONENT_TYPES = {
5
+ action_row: 1,
6
+ text_input: 4
7
+ }.freeze
8
+
9
+ # This builder is used when constructing an ActionRow. All current components must be within an action row, but this can
10
+ # change in the future. A message can have 5 action rows, each action row can hold a weight of 5. Buttons have a weight of 1,
11
+ # and dropdowns have a weight of 5.
12
+ class RowBuilder
13
+ # A mapping of short names to types of input styles. `short` is a single line where `paragraph` is a block.
14
+ TEXT_INPUT_STYLES = {
15
+ short: 1,
16
+ paragraph: 2
17
+ }.freeze
18
+
19
+ # @!visibility private
20
+ def initialize
21
+ @components = []
22
+ end
23
+
24
+ # Add a text input to this action row.
25
+ # @param style [Symbol, Integer] The text input's style type. See {TEXT_INPUT_STYLES}
26
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
27
+ # There is a limit of 100 characters to each custom_id.
28
+ # @param label [String, nil] The text label for the field.
29
+ # @param min_length [Integer, nil] The minimum input length for a text input, min 0, max 4000.
30
+ # @param max_length [Integer, nil] The maximum input length for a text input, min 1, max 4000.
31
+ # @param required [true, false, nil] Whether this component is required to be filled, default true.
32
+ # @param value [String, nil] A pre-filled value for this component, max 4000 characters.
33
+ # @param placeholder [String, nil] Custom placeholder text if the input is empty, max 100 characters
34
+ def text_input(style:, custom_id:, label: nil, min_length: nil, max_length: nil, required: nil, value: nil, placeholder: nil)
35
+ style = TEXT_INPUT_STYLES[style] || style
36
+
37
+ @components << {
38
+ style: style,
39
+ custom_id: custom_id,
40
+ type: COMPONENT_TYPES[:text_input],
41
+ label: label,
42
+ min_length: min_length,
43
+ max_length: max_length,
44
+ required: required,
45
+ value: value,
46
+ placeholder: placeholder
47
+ }
48
+ end
49
+
50
+ # @!visibility private
51
+ def to_h
52
+ {type: COMPONENT_TYPES[:action_row], components: @components}
53
+ end
54
+ end
55
+
56
+ attr_reader :rows
57
+
58
+ def initialize
59
+ @rows = []
60
+
61
+ yield self if block_given?
62
+ end
63
+
64
+ # Add a new ActionRow to the view
65
+ # @yieldparam [RowBuilder]
66
+ def row
67
+ new_row = RowBuilder.new
68
+
69
+ yield new_row
70
+
71
+ @rows << new_row
72
+ end
73
+
74
+ # @!visibility private
75
+ def to_a
76
+ @rows.map(&:to_h)
77
+ end
78
+ end
@@ -0,0 +1,7 @@
1
+ # Webhook support for rubycord
2
+ module Rubycord
3
+ module Webhooks
4
+ # The current version of rubycord-webhooks.
5
+ VERSION = "1.0.0" unless const_defined?(:VERSION)
6
+ end
7
+ end
@@ -0,0 +1,192 @@
1
+ # A reusable view representing a component collection, with builder methods.
2
+ class Rubycord::Webhooks::View
3
+ # Possible button style names and values.
4
+ BUTTON_STYLES = {
5
+ primary: 1,
6
+ secondary: 2,
7
+ success: 3,
8
+ danger: 4,
9
+ link: 5
10
+ }.freeze
11
+
12
+ # Component types.
13
+ # @see https://discord.com/developers/docs/interactions/message-components#component-types
14
+ COMPONENT_TYPES = {
15
+ action_row: 1,
16
+ button: 2,
17
+ string_select: 3,
18
+ # text_input: 4, # (defined in modal.rb)
19
+ user_select: 5,
20
+ role_select: 6,
21
+ mentionable_select: 7,
22
+ channel_select: 8
23
+ }.freeze
24
+
25
+ # This builder is used when constructing an ActionRow. All current components must be within an action row, but this can
26
+ # change in the future. A message can have 5 action rows, each action row can hold a weight of 5. Buttons have a weight of 1,
27
+ # and dropdowns have a weight of 5.
28
+ class RowBuilder
29
+ # @!visibility private
30
+ def initialize
31
+ @components = []
32
+ end
33
+
34
+ # Add a button to this action row.
35
+ # @param style [Symbol, Integer] The button's style type. See {BUTTON_STYLES}
36
+ # @param label [String, nil] The text label for the button. Either a label or emoji must be provided.
37
+ # @param emoji [#to_h, String, Integer] An emoji ID, or unicode emoji to attach to the button. Can also be a object
38
+ # that responds to `#to_h` which returns a hash in the format of `{ id: Integer, name: string }`.
39
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
40
+ # There is a limit of 100 characters to each custom_id.
41
+ # @param disabled [true, false] Whether this button is disabled and shown as greyed out.
42
+ # @param url [String, nil] The URL, when using a link style button.
43
+ def button(style:, label: nil, emoji: nil, custom_id: nil, disabled: nil, url: nil)
44
+ style = BUTTON_STYLES[style] || style
45
+
46
+ emoji = case emoji
47
+ when Integer, String
48
+ emoji.to_i.positive? ? {id: emoji} : {name: emoji}
49
+ else
50
+ emoji&.to_h
51
+ end
52
+
53
+ @components << {type: COMPONENT_TYPES[:button], label: label, emoji: emoji, style: style, custom_id: custom_id, disabled: disabled, url: url}
54
+ end
55
+
56
+ # Add a select string to this action row.
57
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
58
+ # There is a limit of 100 characters to each custom_id.
59
+ # @param options [Array<Hash>] Options that can be selected in this menu. Can also be provided via the yielded builder.
60
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
61
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
62
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
63
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
64
+ # @yieldparam builder [SelectMenuBuilder]
65
+ def string_select(custom_id:, options: [], placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
66
+ builder = SelectMenuBuilder.new(custom_id, options, placeholder, min_values, max_values, disabled, select_type: :string_select)
67
+
68
+ yield builder if block_given?
69
+
70
+ @components << builder.to_h
71
+ end
72
+
73
+ alias_method :select_menu, :string_select
74
+
75
+ # Add a select user to this action row.
76
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
77
+ # There is a limit of 100 characters to each custom_id.
78
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
79
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
80
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
81
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
82
+ def user_select(custom_id:, placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
83
+ @components << SelectMenuBuilder.new(custom_id, [], placeholder, min_values, max_values, disabled, select_type: :user_select).to_h
84
+ end
85
+
86
+ # Add a select role to this action row.
87
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
88
+ # There is a limit of 100 characters to each custom_id.
89
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
90
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
91
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
92
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
93
+ def role_select(custom_id:, placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
94
+ @components << SelectMenuBuilder.new(custom_id, [], placeholder, min_values, max_values, disabled, select_type: :role_select).to_h
95
+ end
96
+
97
+ # Add a select mentionable to this action row.
98
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
99
+ # There is a limit of 100 characters to each custom_id.
100
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
101
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
102
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
103
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
104
+ def mentionable_select(custom_id:, placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
105
+ @components << SelectMenuBuilder.new(custom_id, [], placeholder, min_values, max_values, disabled, select_type: :mentionable_select).to_h
106
+ end
107
+
108
+ # Add a select channel to this action row.
109
+ # @param custom_id [String] Custom IDs are used to pass state to the events that are raised from interactions.
110
+ # There is a limit of 100 characters to each custom_id.
111
+ # @param placeholder [String, nil] Default text to show when no entries are selected.
112
+ # @param min_values [Integer, nil] The minimum amount of values a user must select.
113
+ # @param max_values [Integer, nil] The maximum amount of values a user can select.
114
+ # @param disabled [true, false, nil] Grey out the component to make it unusable.
115
+ def channel_select(custom_id:, placeholder: nil, min_values: nil, max_values: nil, disabled: nil)
116
+ @components << SelectMenuBuilder.new(custom_id, [], placeholder, min_values, max_values, disabled, select_type: :channel_select).to_h
117
+ end
118
+
119
+ # @!visibility private
120
+ def to_h
121
+ {type: COMPONENT_TYPES[:action_row], components: @components}
122
+ end
123
+ end
124
+
125
+ # A builder to assist in adding options to select menus.
126
+ class SelectMenuBuilder
127
+ # @!visibility hidden
128
+ def initialize(custom_id, options = [], placeholder = nil, min_values = nil, max_values = nil, disabled = nil, select_type: :string_select)
129
+ @custom_id = custom_id
130
+ @options = options
131
+ @placeholder = placeholder
132
+ @min_values = min_values
133
+ @max_values = max_values
134
+ @disabled = disabled
135
+ @select_type = select_type
136
+ end
137
+
138
+ # Add an option to this select menu.
139
+ # @param label [String] The title of this option.
140
+ # @param value [String] The value that this option represents.
141
+ # @param description [String, nil] An optional description of the option.
142
+ # @param emoji [#to_h, String, Integer] An emoji ID, or unicode emoji to attach to the button. Can also be a object
143
+ # that responds to `#to_h` which returns a hash in the format of `{ id: Integer, name: string }`.
144
+ # @param default [true, false, nil] Whether this is the default selected option.
145
+ def option(label:, value:, description: nil, emoji: nil, default: nil)
146
+ emoji = case emoji
147
+ when Integer, String
148
+ emoji.to_i.positive? ? {id: emoji} : {name: emoji}
149
+ else
150
+ emoji&.to_h
151
+ end
152
+
153
+ @options << {label: label, value: value, description: description, emoji: emoji, default: default}
154
+ end
155
+
156
+ # @!visibility private
157
+ def to_h
158
+ {
159
+ type: COMPONENT_TYPES[@select_type],
160
+ options: @options,
161
+ placeholder: @placeholder,
162
+ min_values: @min_values,
163
+ max_values: @max_values,
164
+ custom_id: @custom_id,
165
+ disabled: @disabled
166
+ }
167
+ end
168
+ end
169
+
170
+ attr_reader :rows
171
+
172
+ def initialize
173
+ @rows = []
174
+
175
+ yield self if block_given?
176
+ end
177
+
178
+ # Add a new ActionRow to the view
179
+ # @yieldparam [RowBuilder]
180
+ def row
181
+ new_row = RowBuilder.new
182
+
183
+ yield new_row
184
+
185
+ @rows << new_row
186
+ end
187
+
188
+ # @!visibility private
189
+ def to_a
190
+ @rows.map(&:to_h)
191
+ end
192
+ end
@@ -0,0 +1,12 @@
1
+ require "rubycord/webhooks/version"
2
+ require "rubycord/webhooks/embeds"
3
+ require "rubycord/webhooks/client"
4
+ require "rubycord/webhooks/builder"
5
+ require "rubycord/webhooks/view"
6
+ require "rubycord/webhooks/modal"
7
+
8
+ module Rubycord
9
+ # Webhook client
10
+ module Webhooks
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubycord-webhooks
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Dakurei
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-08-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.0
27
+ description: A client for Discord's webhooks to fit alongside [rubycord](https://github.com/dakurei-gems/rubycord).
28
+ email:
29
+ - maxime.palanchini@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/rubycord/webhooks.rb
35
+ - lib/rubycord/webhooks/builder.rb
36
+ - lib/rubycord/webhooks/client.rb
37
+ - lib/rubycord/webhooks/embeds.rb
38
+ - lib/rubycord/webhooks/modal.rb
39
+ - lib/rubycord/webhooks/version.rb
40
+ - lib/rubycord/webhooks/view.rb
41
+ homepage: https://github.com/dakurei-gems/rubycord
42
+ licenses:
43
+ - MIT
44
+ metadata:
45
+ allowed_push_host: https://rubygems.org
46
+ homepage_uri: https://github.com/dakurei-gems/rubycord
47
+ source_code_uri: https://github.com/dakurei-gems/rubycord
48
+ changelog_uri: https://github.com/dakurei-gems/rubycord/blob/main/CHANGELOG.md
49
+ post_install_message:
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: 3.1.3
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ requirements: []
64
+ rubygems_version: 3.5.17
65
+ signing_key:
66
+ specification_version: 4
67
+ summary: Webhook client for rubycord
68
+ test_files: []