onyxcord 2.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. checksums.yaml +4 -4
  2. data/lib/onyxcord/application_commands/command.rb +4 -97
  3. data/lib/onyxcord/application_commands/context.rb +4 -94
  4. data/lib/onyxcord/application_commands/option.rb +4 -75
  5. data/lib/onyxcord/application_commands/registry.rb +4 -45
  6. data/lib/onyxcord/application_commands.rb +8 -5
  7. data/lib/onyxcord/bot.rb +24 -1759
  8. data/lib/onyxcord/{cache.rb → cache/manager.rb} +16 -14
  9. data/lib/onyxcord/cache/stores/gateway.rb +272 -0
  10. data/lib/onyxcord/commands/bot/channels.rb +48 -0
  11. data/lib/onyxcord/commands/bot/execution.rb +174 -0
  12. data/lib/onyxcord/commands/bot/message_dispatch.rb +58 -0
  13. data/lib/onyxcord/commands/bot/permissions.rb +72 -0
  14. data/lib/onyxcord/commands/bot.rb +209 -0
  15. data/lib/onyxcord/commands/container.rb +21 -2
  16. data/lib/onyxcord/commands/parser.rb +30 -1
  17. data/lib/onyxcord/container.rb +16 -960
  18. data/lib/onyxcord/core/bot/application_commands.rb +210 -0
  19. data/lib/onyxcord/core/bot/awaits.rb +112 -0
  20. data/lib/onyxcord/core/bot/invites.rb +42 -0
  21. data/lib/onyxcord/core/bot/messaging.rb +161 -0
  22. data/lib/onyxcord/core/bot/oauth.rb +27 -0
  23. data/lib/onyxcord/core/bot/presence.rb +103 -0
  24. data/lib/onyxcord/core/bot/runtime.rb +183 -0
  25. data/lib/onyxcord/core/bot/voice.rb +69 -0
  26. data/lib/onyxcord/{logger.rb → core/logger.rb} +5 -0
  27. data/lib/onyxcord/core/version.rb +5 -0
  28. data/lib/onyxcord/events/await/base.rb +48 -0
  29. data/lib/onyxcord/events/await.rb +1 -46
  30. data/lib/onyxcord/events/ban/base.rb +54 -0
  31. data/lib/onyxcord/events/ban/remove.rb +11 -0
  32. data/lib/onyxcord/events/bans.rb +2 -58
  33. data/lib/onyxcord/events/channels/base.rb +91 -0
  34. data/lib/onyxcord/events/channels/delete.rb +73 -0
  35. data/lib/onyxcord/events/channels/pins.rb +44 -0
  36. data/lib/onyxcord/events/channels/recipients.rb +77 -0
  37. data/lib/onyxcord/events/channels.rb +4 -239
  38. data/lib/onyxcord/events/guilds/audit_logs.rb +79 -0
  39. data/lib/onyxcord/events/guilds/base.rb +97 -0
  40. data/lib/onyxcord/events/guilds/emoji.rb +147 -0
  41. data/lib/onyxcord/events/guilds.rb +3 -267
  42. data/lib/onyxcord/events/handlers/channels.rb +133 -0
  43. data/lib/onyxcord/events/handlers/core.rb +146 -0
  44. data/lib/onyxcord/events/handlers/guilds.rb +375 -0
  45. data/lib/onyxcord/events/handlers/interactions.rb +238 -0
  46. data/lib/onyxcord/events/handlers/lifetime.rb +71 -0
  47. data/lib/onyxcord/events/handlers/messages.rb +218 -0
  48. data/lib/onyxcord/events/handlers/presence.rb +56 -0
  49. data/lib/onyxcord/events/handlers/raw.rb +39 -0
  50. data/lib/onyxcord/events/handlers/reactions.rb +98 -0
  51. data/lib/onyxcord/events/handlers/scheduled_events.rb +243 -0
  52. data/lib/onyxcord/events/handlers/voice.rb +46 -0
  53. data/lib/onyxcord/events/integration/base.rb +45 -0
  54. data/lib/onyxcord/events/integration/create.rb +11 -0
  55. data/lib/onyxcord/events/integration/delete.rb +48 -0
  56. data/lib/onyxcord/events/integration/update.rb +11 -0
  57. data/lib/onyxcord/events/integrations.rb +4 -98
  58. data/lib/onyxcord/events/interactions/application_commands.rb +185 -0
  59. data/lib/onyxcord/events/interactions/autocomplete.rb +62 -0
  60. data/lib/onyxcord/events/interactions/base.rb +175 -0
  61. data/lib/onyxcord/events/interactions/components.rb +221 -0
  62. data/lib/onyxcord/events/interactions/permissions.rb +53 -0
  63. data/lib/onyxcord/events/interactions.rb +5 -622
  64. data/lib/onyxcord/events/invite/create.rb +79 -0
  65. data/lib/onyxcord/events/invite/delete.rb +55 -0
  66. data/lib/onyxcord/events/invites.rb +2 -125
  67. data/lib/onyxcord/events/lifetime/base.rb +31 -0
  68. data/lib/onyxcord/events/lifetime.rb +1 -29
  69. data/lib/onyxcord/events/member/add.rb +12 -0
  70. data/lib/onyxcord/events/member/base.rb +67 -0
  71. data/lib/onyxcord/events/member/delete.rb +21 -0
  72. data/lib/onyxcord/events/member/update.rb +25 -0
  73. data/lib/onyxcord/events/members.rb +4 -108
  74. data/lib/onyxcord/events/message/base.rb +295 -0
  75. data/lib/onyxcord/events/message/ids.rb +71 -0
  76. data/lib/onyxcord/events/message/mentions.rb +55 -0
  77. data/lib/onyxcord/events/message/updates.rb +27 -0
  78. data/lib/onyxcord/events/message.rb +4 -397
  79. data/lib/onyxcord/events/poll/add.rb +11 -0
  80. data/lib/onyxcord/events/poll/base.rb +106 -0
  81. data/lib/onyxcord/events/poll/remove.rb +11 -0
  82. data/lib/onyxcord/events/polls.rb +3 -116
  83. data/lib/onyxcord/events/presence/playing.rb +77 -0
  84. data/lib/onyxcord/events/presence/status.rb +60 -0
  85. data/lib/onyxcord/events/presence.rb +2 -129
  86. data/lib/onyxcord/events/raw/base.rb +74 -0
  87. data/lib/onyxcord/events/raw.rb +1 -72
  88. data/lib/onyxcord/events/reactions/base.rb +143 -0
  89. data/lib/onyxcord/events/reactions/clear.rb +99 -0
  90. data/lib/onyxcord/events/reactions.rb +2 -216
  91. data/lib/onyxcord/events/role/create.rb +46 -0
  92. data/lib/onyxcord/events/role/delete.rb +40 -0
  93. data/lib/onyxcord/events/role/update.rb +11 -0
  94. data/lib/onyxcord/events/roles.rb +3 -85
  95. data/lib/onyxcord/events/scheduled_events/events.rb +112 -0
  96. data/lib/onyxcord/events/scheduled_events/users.rb +91 -0
  97. data/lib/onyxcord/events/scheduled_events.rb +2 -169
  98. data/lib/onyxcord/events/thread/base.rb +49 -0
  99. data/lib/onyxcord/events/thread/members.rb +44 -0
  100. data/lib/onyxcord/events/thread/update.rb +18 -0
  101. data/lib/onyxcord/events/threads.rb +3 -98
  102. data/lib/onyxcord/events/typing/base.rb +73 -0
  103. data/lib/onyxcord/events/typing.rb +1 -71
  104. data/lib/onyxcord/events/voice/server_update.rb +48 -0
  105. data/lib/onyxcord/events/voice/state_update.rb +137 -0
  106. data/lib/onyxcord/events/voice_server_update.rb +2 -46
  107. data/lib/onyxcord/events/voice_state_update.rb +2 -135
  108. data/lib/onyxcord/events/webhook/update.rb +65 -0
  109. data/lib/onyxcord/events/webhooks.rb +1 -63
  110. data/lib/onyxcord/gateway/client.rb +460 -0
  111. data/lib/onyxcord/interactions/command.rb +120 -0
  112. data/lib/onyxcord/interactions/context.rb +109 -0
  113. data/lib/onyxcord/interactions/internal/application_command.rb +203 -0
  114. data/lib/onyxcord/interactions/internal/message.rb +152 -0
  115. data/lib/onyxcord/interactions/internal/metadata.rb +109 -0
  116. data/lib/onyxcord/interactions/internal/option_builder.rb +230 -0
  117. data/lib/onyxcord/interactions/internal/permission_builder.rb +90 -0
  118. data/lib/onyxcord/interactions/option.rb +88 -0
  119. data/lib/onyxcord/interactions/registry.rb +50 -0
  120. data/lib/onyxcord/interactions.rb +16 -0
  121. data/lib/onyxcord/internal/async_runtime.rb +32 -0
  122. data/lib/onyxcord/internal/event_bus.rb +591 -0
  123. data/lib/onyxcord/internal/event_executor.rb +155 -0
  124. data/lib/onyxcord/internal/gateway/opcodes.rb +22 -0
  125. data/lib/onyxcord/internal/gateway/session.rb +45 -0
  126. data/lib/onyxcord/internal/http.rb +189 -0
  127. data/lib/onyxcord/internal/json.rb +51 -0
  128. data/lib/onyxcord/{message_payload.rb → internal/message_payload.rb} +3 -3
  129. data/lib/onyxcord/internal/rate_limiter/async_rest.rb +151 -0
  130. data/lib/onyxcord/internal/rate_limiter/gateway.rb +44 -0
  131. data/lib/onyxcord/internal/rate_limiter/rest.rb +144 -0
  132. data/lib/onyxcord/internal/websocket.rb +79 -0
  133. data/lib/onyxcord/light/data.rb +1 -1
  134. data/lib/onyxcord/light/integrations.rb +1 -1
  135. data/lib/onyxcord/light/light_bot.rb +7 -7
  136. data/lib/onyxcord/{data → models}/activity.rb +2 -2
  137. data/lib/onyxcord/{data → models}/application.rb +3 -3
  138. data/lib/onyxcord/{data → models}/avatar_decoration.rb +1 -1
  139. data/lib/onyxcord/{data → models}/channel.rb +23 -23
  140. data/lib/onyxcord/{data → models}/collectibles.rb +1 -1
  141. data/lib/onyxcord/{data → models}/emoji.rb +1 -1
  142. data/lib/onyxcord/models/interaction.rb +450 -0
  143. data/lib/onyxcord/{data → models}/invite.rb +1 -1
  144. data/lib/onyxcord/{data → models}/member.rb +11 -11
  145. data/lib/onyxcord/{data → models}/message.rb +18 -14
  146. data/lib/onyxcord/{data → models}/poll.rb +2 -2
  147. data/lib/onyxcord/{data → models}/primary_server.rb +1 -1
  148. data/lib/onyxcord/{data → models}/profile.rb +4 -4
  149. data/lib/onyxcord/{data → models}/role.rb +6 -12
  150. data/lib/onyxcord/{data → models}/scheduled_event.rb +5 -5
  151. data/lib/onyxcord/{data → models}/server.rb +41 -41
  152. data/lib/onyxcord/{data → models}/server_preview.rb +2 -2
  153. data/lib/onyxcord/{data → models}/team.rb +1 -1
  154. data/lib/onyxcord/{data → models}/user.rb +5 -5
  155. data/lib/onyxcord/{data → models}/webhook.rb +10 -10
  156. data/lib/onyxcord/models.rb +57 -0
  157. data/lib/onyxcord/{api.rb → rest/client.rb} +23 -22
  158. data/lib/onyxcord/{api → rest/routes}/application.rb +79 -57
  159. data/lib/onyxcord/rest/routes/channel/base.rb +73 -0
  160. data/lib/onyxcord/rest/routes/channel/groups.rb +78 -0
  161. data/lib/onyxcord/rest/routes/channel/messages.rb +130 -0
  162. data/lib/onyxcord/rest/routes/channel/permissions.rb +73 -0
  163. data/lib/onyxcord/rest/routes/channel/pins.rb +45 -0
  164. data/lib/onyxcord/rest/routes/channel/polls.rb +32 -0
  165. data/lib/onyxcord/rest/routes/channel/reactions.rb +86 -0
  166. data/lib/onyxcord/rest/routes/channel/threads.rb +176 -0
  167. data/lib/onyxcord/rest/routes/channel/webhooks.rb +47 -0
  168. data/lib/onyxcord/rest/routes/channel.rb +12 -0
  169. data/lib/onyxcord/{api/interaction.rb → rest/routes/interaction/base.rb} +7 -25
  170. data/lib/onyxcord/rest/routes/interaction/response.rb +24 -0
  171. data/lib/onyxcord/rest/routes/interaction.rb +4 -0
  172. data/lib/onyxcord/{api → rest/routes}/invite.rb +7 -7
  173. data/lib/onyxcord/rest/routes/server/admin.rb +174 -0
  174. data/lib/onyxcord/rest/routes/server/assets.rb +25 -0
  175. data/lib/onyxcord/rest/routes/server/bans.rb +67 -0
  176. data/lib/onyxcord/rest/routes/server/base.rb +77 -0
  177. data/lib/onyxcord/rest/routes/server/channels.rb +58 -0
  178. data/lib/onyxcord/rest/routes/server/emoji.rb +48 -0
  179. data/lib/onyxcord/rest/routes/server/members.rb +109 -0
  180. data/lib/onyxcord/rest/routes/server/messages.rb +19 -0
  181. data/lib/onyxcord/rest/routes/server/roles.rb +156 -0
  182. data/lib/onyxcord/rest/routes/server/scheduled_events.rb +86 -0
  183. data/lib/onyxcord/rest/routes/server.rb +12 -0
  184. data/lib/onyxcord/{api → rest/routes}/user.rb +23 -23
  185. data/lib/onyxcord/{api → rest/routes}/webhook.rb +22 -22
  186. data/lib/onyxcord/{allowed_mentions.rb → utils/allowed_mentions.rb} +1 -1
  187. data/lib/onyxcord/utils/timestamp.rb +69 -0
  188. data/lib/onyxcord/voice/{voice_bot.rb → client.rb} +4 -4
  189. data/lib/onyxcord/voice/encoder.rb +1 -1
  190. data/lib/onyxcord/voice/network/udp.rb +135 -0
  191. data/lib/onyxcord/voice/network/websocket.rb +225 -0
  192. data/lib/onyxcord/voice/network.rb +5 -357
  193. data/lib/onyxcord/webhooks/builder.rb +1 -1
  194. data/lib/onyxcord/webhooks/client.rb +13 -13
  195. data/lib/onyxcord/webhooks/modal/group_builder.rb +55 -0
  196. data/lib/onyxcord/webhooks/modal/label_builder.rb +183 -0
  197. data/lib/onyxcord/webhooks/modal.rb +2 -239
  198. data/lib/onyxcord/webhooks/version.rb +3 -3
  199. data/lib/onyxcord/webhooks/view/container_builder.rb +80 -0
  200. data/lib/onyxcord/webhooks/view/file_builder.rb +24 -0
  201. data/lib/onyxcord/webhooks/view/media_gallery_builder.rb +50 -0
  202. data/lib/onyxcord/webhooks/view/row_builder.rb +120 -0
  203. data/lib/onyxcord/webhooks/view/section_builder.rb +61 -0
  204. data/lib/onyxcord/webhooks/view/select_menu_builder.rb +77 -0
  205. data/lib/onyxcord/webhooks/view/separator_builder.rb +22 -0
  206. data/lib/onyxcord/webhooks/view/text_display_builder.rb +20 -0
  207. data/lib/onyxcord/webhooks/view.rb +9 -425
  208. data/lib/onyxcord.rb +106 -42
  209. metadata +207 -92
  210. data/.github/CONTRIBUTING.md +0 -13
  211. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
  212. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -24
  213. data/.github/pull_request_template.md +0 -37
  214. data/.github/workflows/ci.yml +0 -78
  215. data/.github/workflows/codeql.yml +0 -65
  216. data/.github/workflows/deploy.yml +0 -54
  217. data/.github/workflows/release.yml +0 -51
  218. data/.gitignore +0 -17
  219. data/.markdownlint.json +0 -4
  220. data/.overcommit.yml +0 -7
  221. data/.rspec +0 -2
  222. data/.rubocop.yml +0 -129
  223. data/.yardopts +0 -1
  224. data/CHANGELOG.md +0 -257
  225. data/Gemfile +0 -6
  226. data/LICENSE.txt +0 -21
  227. data/README.md +0 -448
  228. data/Rakefile +0 -13
  229. data/lib/onyxcord/api/channel.rb +0 -703
  230. data/lib/onyxcord/api/server.rb +0 -775
  231. data/lib/onyxcord/async/runtime.rb +0 -30
  232. data/lib/onyxcord/commands/command_bot.rb +0 -505
  233. data/lib/onyxcord/data/interaction.rb +0 -1151
  234. data/lib/onyxcord/data.rb +0 -57
  235. data/lib/onyxcord/event_executor.rb +0 -153
  236. data/lib/onyxcord/gateway.rb +0 -505
  237. data/lib/onyxcord/http.rb +0 -186
  238. data/lib/onyxcord/json.rb +0 -49
  239. data/lib/onyxcord/rate_limiter/async_rest.rb +0 -150
  240. data/lib/onyxcord/rate_limiter/gateway.rb +0 -42
  241. data/lib/onyxcord/rate_limiter/rest.rb +0 -142
  242. data/lib/onyxcord/version.rb +0 -7
  243. data/lib/onyxcord/websocket.rb +0 -77
  244. data/onyxcord.gemspec +0 -63
  245. /data/lib/onyxcord/{configuration.rb → core/configuration.rb} +0 -0
  246. /data/lib/onyxcord/{errors.rb → core/errors.rb} +0 -0
  247. /data/lib/onyxcord/{upload.rb → internal/upload.rb} +0 -0
  248. /data/lib/onyxcord/{data → models}/attachment.rb +0 -0
  249. /data/lib/onyxcord/{data → models}/audit_logs.rb +0 -0
  250. /data/lib/onyxcord/{data → models}/call.rb +0 -0
  251. /data/lib/onyxcord/{data → models}/channel_tag.rb +0 -0
  252. /data/lib/onyxcord/{data → models}/component.rb +0 -0
  253. /data/lib/onyxcord/{data → models}/embed.rb +0 -0
  254. /data/lib/onyxcord/{data → models}/install_params.rb +0 -0
  255. /data/lib/onyxcord/{data → models}/integration.rb +0 -0
  256. /data/lib/onyxcord/{data → models}/message_activity.rb +0 -0
  257. /data/lib/onyxcord/{data → models}/overwrite.rb +0 -0
  258. /data/lib/onyxcord/{data → models}/reaction.rb +0 -0
  259. /data/lib/onyxcord/{data → models}/recipient.rb +0 -0
  260. /data/lib/onyxcord/{data → models}/role_connection_data.rb +0 -0
  261. /data/lib/onyxcord/{data → models}/role_subscription.rb +0 -0
  262. /data/lib/onyxcord/{data → models}/snapshot.rb +0 -0
  263. /data/lib/onyxcord/{data → models}/timestamp.rb +0 -0
  264. /data/lib/onyxcord/{data → models}/voice_region.rb +0 -0
  265. /data/lib/onyxcord/{data → models}/voice_state.rb +0 -0
  266. /data/lib/onyxcord/{colour_rgb.rb → utils/colour_rgb.rb} +0 -0
  267. /data/lib/onyxcord/{id_object.rb → utils/id_object.rb} +0 -0
  268. /data/lib/onyxcord/{message_components.rb → utils/message_components.rb} +0 -0
  269. /data/lib/onyxcord/{paginator.rb → utils/paginator.rb} +0 -0
  270. /data/lib/onyxcord/{permissions.rb → utils/permissions.rb} +0 -0
@@ -1,1151 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'onyxcord/webhooks'
4
- require 'onyxcord/message_payload'
5
-
6
- module OnyxCord
7
- # Base class for interaction objects.
8
- class Interaction
9
- include IDObject
10
-
11
- # Interaction types.
12
- # @see https://discord.com/developers/docs/interactions/slash-commands#interaction-interactiontype
13
- TYPES = {
14
- ping: 1,
15
- command: 2,
16
- component: 3,
17
- autocomplete: 4,
18
- modal_submit: 5
19
- }.freeze
20
-
21
- # Interaction response types.
22
- # @see https://discord.com/developers/docs/interactions/slash-commands#interaction-response-interactioncallbacktype
23
- CALLBACK_TYPES = {
24
- pong: 1,
25
- channel_message: 4,
26
- deferred_message: 5,
27
- deferred_update: 6,
28
- update_message: 7,
29
- autocomplete: 8,
30
- modal: 9
31
- }.freeze
32
-
33
- # Interaction context types.
34
- # @see https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-context-types
35
- CONTEXTS = {
36
- server: 0,
37
- bot_dm: 1,
38
- private_channel: 2
39
- }.freeze
40
-
41
- # Application integration types.
42
- # @see https://discord.com/developers/docs/resources/application#application-object-application-integration-types
43
- INTEGRATION_TYPES = {
44
- server: 0,
45
- user: 1
46
- }.freeze
47
-
48
- # @return [User, Member] The user that initiated the interaction.
49
- attr_reader :user
50
-
51
- # @return [Integer, nil] The ID of the server this interaction originates from.
52
- attr_reader :server_id
53
-
54
- # @return [Integer] The ID of the channel this interaction originates from.
55
- attr_reader :channel_id
56
-
57
- # @return [Channel] The channel where this interaction originates from.
58
- attr_reader :channel
59
-
60
- # @return [Integer] The ID of the application associated with this interaction.
61
- attr_reader :application_id
62
-
63
- # @return [String] The interaction token.
64
- attr_reader :token
65
-
66
- # @!visibility private
67
- # @return [Integer] Currently pointless
68
- attr_reader :version
69
-
70
- # @return [Integer] The type of this interaction.
71
- # @see TYPES
72
- attr_reader :type
73
-
74
- # @return [Hash] The interaction data.
75
- attr_reader :data
76
-
77
- # @return [Interactions::Message, nil] The message associated with this interaction.
78
- attr_reader :message
79
-
80
- # @return [Array<ActionRow>] The modal components associated with this interaction.
81
- attr_reader :components
82
-
83
- # @return [Permissions] The permissions the application has where this interaction originates from.
84
- attr_reader :application_permissions
85
-
86
- # @return [String] The selected language of the user that initiated this interaction.
87
- attr_reader :user_locale
88
-
89
- # @return [String, nil] The selected language of the server this interaction originates from.
90
- attr_reader :server_locale
91
-
92
- # @return [Integer] The context of where this interaction was initiated from.
93
- attr_reader :context
94
-
95
- # @return [Integer] The maximum number of bytes an attachment can have when responding to this interaction.
96
- attr_reader :max_attachment_size
97
-
98
- # @return [Array<Symbol>] The features of the server where this interaction was initiated from.
99
- attr_reader :server_features
100
-
101
- # @!visibility private
102
- def initialize(data, bot)
103
- @bot = bot
104
-
105
- @id = data['id'].to_i
106
- @application_id = data['application_id'].to_i
107
- @type = data['type']
108
- @message = Interactions::Message.new(data['message'], @bot, self) if data['message']
109
- @data = data['data']
110
- @server_id = data['guild_id']&.to_i
111
- @channel_id = data['channel_id']&.to_i
112
- @channel = bot.ensure_channel(data['channel']) if data['channel']
113
- @user = begin
114
- if data['member'] && data['member']['user']
115
- data['member']['guild_id'] = @server_id
116
- server = bot.servers ? bot.servers[@server_id] : nil
117
- OnyxCord::Member.new(data['member'], server, bot)
118
- elsif data['user']
119
- bot.ensure_user(data['user'])
120
- end
121
- rescue StandardError => e
122
- OnyxCord::LOGGER.error("Failed to parse interaction user/member: #{e}")
123
- nil
124
- end
125
- @token = data['token']
126
- @version = data['version']
127
- @components = @data['components']&.filter_map { |component| Components.from_data(component, @bot) } || []
128
- @application_permissions = Permissions.new(data['app_permissions']) if data['app_permissions']
129
- @user_locale = data['locale']
130
- @server_locale = data['guild_locale']
131
- @context = data['context']
132
- @max_attachment_size = data['attachment_size_limit']
133
- @integration_owners = data['authorizing_integration_owners']&.to_h { |key, value| [key.to_i, value.to_i] }
134
- @server_features = data['guild'] ? data['guild']['features']&.map { |feature| feature.downcase.to_sym } : []
135
- end
136
-
137
- # Respond to the creation of this interaction. An interaction must be responded to or deferred,
138
- # The response may be modified with {Interaction#edit_response} or deleted with {Interaction#delete_response}.
139
- # Further messages can be sent with {Interaction#send_message}.
140
- # @param content [String] The content of the message.
141
- # @param tts [true, false]
142
- # @param embeds [Array<Hash, Webhooks::Embed>] The embeds for the message.
143
- # @param allowed_mentions [Hash, AllowedMentions] Mentions that can ping on this message.
144
- # @param flags [Integer] Message flags.
145
- # @param ephemeral [true, false] Whether this message should only be visible to the interaction initiator.
146
- # @param wait [true, false] Whether this method should return a Message object of the interaction response.
147
- # @param components [Array<#to_h>] An array of components.
148
- # @param attachments [Array<File>] Files that can be referenced in embeds and components via `attachment://file.png`.
149
- # @param has_components [true, false] Whether this message includes any V2 components. Enabling this disables sending content, polls, and embeds.
150
- # @param poll [Hash, Poll::Builder, Poll, nil] The poll that should be attached to this message.
151
- # @yieldparam builder [Webhooks::Builder] An optional message builder. Arguments passed to the method overwrite builder data.
152
- # @yieldparam view [Webhooks::View] A builder for creating interaction components.
153
- def respond(content: nil, tts: nil, embeds: nil, allowed_mentions: nil, flags: 0, ephemeral: nil, wait: false, components: nil, attachments: nil, has_components: false, components_v2: false, poll: nil)
154
- flags |= 1 << 6 if ephemeral
155
-
156
- builder = OnyxCord::Webhooks::Builder.new
157
- view = OnyxCord::Webhooks::View.new
158
-
159
- # Set builder defaults from parameters
160
- prepare_builder(builder, content, embeds, allowed_mentions, poll)
161
- yield(builder, view) if block_given?
162
-
163
- components ||= view
164
- flags = OnyxCord::MessageComponents.apply_v2_flag(flags, components, force: has_components || components_v2)
165
- data = builder.to_json_hash
166
-
167
- response = OnyxCord::API::Interaction.create_interaction_response(@token, @id, CALLBACK_TYPES[:channel_message], data[:content], tts, data[:embeds], data[:allowed_mentions], flags, components.to_a, attachments, nil, wait, data[:poll])
168
- return unless wait
169
-
170
- Interactions::Message.new(JSON.parse(response)['resource']['message'], @bot, self)
171
- end
172
-
173
- # Defer an interaction, setting a temporary response that can be later overriden by {Interaction#send_message}.
174
- # This method is used when you want to use a single message for your response but require additional processing time, or to simply ack
175
- # an interaction so an error is not displayed.
176
- # @param flags [Integer] Message flags.
177
- # @param ephemeral [true, false] Whether this message should only be visible to the interaction initiator.
178
- def defer(flags: 0, ephemeral: true)
179
- flags |= 1 << 6 if ephemeral
180
-
181
- OnyxCord::API::Interaction.create_interaction_response(@token, @id, CALLBACK_TYPES[:deferred_message], nil, nil, nil, nil, flags)
182
- nil
183
- end
184
-
185
- # Defer an update to an interaction. This is can only currently used by Button interactions.
186
- def defer_update
187
- OnyxCord::API::Interaction.create_interaction_response(@token, @id, CALLBACK_TYPES[:deferred_update])
188
- end
189
-
190
- # Create a modal as a response.
191
- # @param title [String] The title of the modal being shown.
192
- # @param custom_id [String] The custom_id used to identify the modal and store data.
193
- # @param components [Array<Component, Hash>, nil] An array of components. These can be defined through the block as well.
194
- # @yieldparam [OnyxCord::Webhooks::Modal] A builder for the modal's components.
195
- def show_modal(title:, custom_id:, components: nil)
196
- if block_given?
197
- modal_builder = OnyxCord::Webhooks::Modal.new
198
- yield modal_builder
199
-
200
- components = modal_builder.to_a
201
- end
202
-
203
- OnyxCord::API::Interaction.create_interaction_modal_response(@token, @id, custom_id, title, components.to_a) unless type == Interaction::TYPES[:modal_submit]
204
- nil
205
- end
206
-
207
- # Respond to the creation of this interaction. An interaction must be responded to or deferred,
208
- # The response may be modified with {Interaction#edit_response} or deleted with {Interaction#delete_response}.
209
- # Further messages can be sent with {Interaction#send_message}.
210
- # @param content [String] The content of the message.
211
- # @param tts [true, false]
212
- # @param embeds [Array<Hash, Webhooks::Embed>] The embeds for the message.
213
- # @param allowed_mentions [Hash, AllowedMentions] Mentions that can ping on this message.
214
- # @param flags [Integer] Message flags.
215
- # @param ephemeral [true, false] Whether this message should only be visible to the interaction initiator.
216
- # @param wait [true, false] Whether this method should return a Message object of the interaction response.
217
- # @param components [Array<#to_h>] An array of components.
218
- # @param attachments [Array<File>] Files that can be referenced in embeds and components via `attachment://file.png`.
219
- # @param has_components [true, false] Whether this message includes any V2 components. Enabling this disables sending content, polls, and embeds.
220
- # @param poll [Hash, Poll::Builder, Poll, nil] The poll that should be attached to this message.
221
- # @yieldparam builder [Webhooks::Builder] An optional message builder. Arguments passed to the method overwrite builder data.
222
- # @yieldparam view [Webhooks::View] A builder for creating interaction components.
223
- def update_message(content: nil, tts: nil, embeds: nil, allowed_mentions: nil, flags: 0, ephemeral: nil, wait: false, components: nil, attachments: nil, has_components: false, components_v2: false, poll: nil)
224
- flags |= 1 << 6 if ephemeral
225
-
226
- builder = OnyxCord::Webhooks::Builder.new
227
- view = OnyxCord::Webhooks::View.new
228
-
229
- prepare_builder(builder, content, embeds, allowed_mentions, poll)
230
- yield(builder, view) if block_given?
231
-
232
- components ||= view
233
- flags = OnyxCord::MessageComponents.apply_v2_flag(flags, components, force: has_components || components_v2)
234
- data = builder.to_json_hash
235
-
236
- response = OnyxCord::API::Interaction.create_interaction_response(@token, @id, CALLBACK_TYPES[:update_message], data[:content], tts, data[:embeds], data[:allowed_mentions], flags, components.to_a, attachments, nil, wait, data[:poll])
237
- return unless wait
238
-
239
- Interactions::Message.new(JSON.parse(response)['resource']['message'], @bot, self)
240
- end
241
-
242
- # Edit the original response to this interaction.
243
- # @param content [String] The content of the message.
244
- # @param embeds [Array<Hash, Webhooks::Embed>] The embeds for the message.
245
- # @param allowed_mentions [Hash, AllowedMentions] Mentions that can ping on this message.
246
- # @param flags [Integer] Message flags.
247
- # @param components [Array<#to_h>] An array of components.
248
- # @param attachments [Array<File>] Files that can be referenced in embeds and components via `attachment://file.png`.
249
- # @param has_components [true, false] Whether this message includes any V2 components. Enabling this disables sending content, polls, and embeds.
250
- # @param poll [Hash, Poll::Builder, Poll, nil] The poll that should be attached to this message.
251
- # @return [InteractionMessage] The updated response message.
252
- # @yieldparam builder [Webhooks::Builder] An optional message builder. Arguments passed to the method overwrite builder data.
253
- def edit_response(content: nil, embeds: nil, allowed_mentions: nil, flags: 0, components: nil, attachments: nil, has_components: false, components_v2: false, poll: nil)
254
- builder = OnyxCord::Webhooks::Builder.new
255
- view = OnyxCord::Webhooks::View.new
256
-
257
- prepare_builder(builder, content, embeds, allowed_mentions, poll)
258
- yield(builder, view) if block_given?
259
-
260
- components ||= view
261
- flags = OnyxCord::MessageComponents.apply_v2_flag(flags, components, force: has_components || components_v2)
262
- data = builder.to_json_hash
263
- resp = OnyxCord::API::Interaction.edit_original_interaction_response(@token, @application_id, edit_content(content, data), edit_embeds(embeds, data), data[:allowed_mentions], components.to_a, attachments, flags, data[:poll])
264
-
265
- Interactions::Message.new(JSON.parse(resp), @bot, self)
266
- end
267
-
268
- # Delete the original interaction response.
269
- def delete_response
270
- OnyxCord::API::Interaction.delete_original_interaction_response(@token, @application_id)
271
- end
272
-
273
- # @param content [String] The content of the message.
274
- # @param tts [true, false]
275
- # @param embeds [Array<Hash, Webhooks::Embed>] The embeds for the message.
276
- # @param allowed_mentions [Hash, AllowedMentions] Mentions that can ping on this message.
277
- # @param flags [Integer] Message flags.
278
- # @param ephemeral [true, false] Whether this message should only be visible to the interaction initiator.
279
- # @param attachments [Array<File>] Files that can be referenced in embeds and components via `attachment://file.png`.
280
- # @param has_components [true, false] Whether this message includes any V2 components. Enabling this disables sending content, polls, and embeds.
281
- # @param poll [Hash, Poll::Builder, Poll, nil] The poll that should be attached to this message.
282
- # @yieldparam builder [Webhooks::Builder] An optional message builder. Arguments passed to the method overwrite builder data.
283
- def send_message(content: nil, embeds: nil, tts: false, allowed_mentions: nil, flags: 0, ephemeral: false, components: nil, attachments: nil, has_components: false, components_v2: false, poll: nil)
284
- flags |= 64 if ephemeral
285
-
286
- builder = OnyxCord::Webhooks::Builder.new
287
- view = OnyxCord::Webhooks::View.new
288
-
289
- prepare_builder(builder, content, embeds, allowed_mentions, poll)
290
- yield(builder, view) if block_given?
291
-
292
- components ||= view
293
- flags = OnyxCord::MessageComponents.apply_v2_flag(flags, components, force: has_components || components_v2)
294
- data = builder.to_json_hash
295
-
296
- resp = OnyxCord::API::Webhook.token_execute_webhook(
297
- @token, @application_id, true, data[:content], nil, nil, tts, nil, data[:embeds], data[:allowed_mentions], flags, components.to_a, attachments, data[:poll]
298
- )
299
- Interactions::Message.new(JSON.parse(resp), @bot, self)
300
- end
301
-
302
- alias edit_original edit_response
303
- alias delete_original delete_response
304
- alias followup send_message
305
-
306
- # @param message [String, Integer, InteractionMessage, Message] The message created by this interaction to be edited.
307
- # @param content [String] The message content.
308
- # @param embeds [Array<Hash, Webhooks::Embed>] The embeds for the message.
309
- # @param allowed_mentions [Hash, AllowedMentions] Mentions that can ping on this message.
310
- # @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`.
311
- # @param flags [Integer] Message flags.
312
- # @param has_components [true, false] Whether this message includes any V2 components. Enabling this disables sending content, polls, and embeds.
313
- # @param poll [Hash, Poll::Builder, Poll, nil] The poll that should be attached to this message.
314
- # @yieldparam builder [Webhooks::Builder] An optional message builder. Arguments passed to the method overwrite builder data.
315
- def edit_message(message, content: nil, embeds: nil, allowed_mentions: nil, components: nil, attachments: nil, flags: 0, has_components: false, components_v2: false, poll: nil)
316
- builder = OnyxCord::Webhooks::Builder.new
317
- view = OnyxCord::Webhooks::View.new
318
-
319
- prepare_builder(builder, content, embeds, allowed_mentions, poll)
320
- yield(builder, view) if block_given?
321
-
322
- components ||= view
323
- flags = OnyxCord::MessageComponents.apply_v2_flag(flags, components, force: has_components || components_v2)
324
- data = builder.to_json_hash
325
-
326
- resp = OnyxCord::API::Webhook.token_edit_message(
327
- @token, @application_id, message.resolve_id, edit_content(content, data), edit_embeds(embeds, data), data[:allowed_mentions], components.to_a, attachments, flags, data[:poll]
328
- )
329
- Interactions::Message.new(JSON.parse(resp), @bot, self)
330
- end
331
-
332
- # @param message [Integer, String, InteractionMessage, Message] The message created by this interaction to be deleted.
333
- def delete_message(message)
334
- OnyxCord::API::Webhook.token_delete_message(@token, @application_id, message.resolve_id)
335
- nil
336
- end
337
-
338
- # Show autocomplete choices as a response.
339
- # @param choices [Array<Hash>, Hash] Array of autocomplete choices to show the user.
340
- def show_autocomplete_choices(choices)
341
- choices = choices.map { |name, value| { name: name, value: value } } unless choices.is_a?(Array)
342
- OnyxCord::API::Interaction.create_interaction_response(@token, @id, CALLBACK_TYPES[:autocomplete], nil, nil, nil, nil, nil, nil, nil, choices)
343
- nil
344
- end
345
-
346
- # Get the server associated with the interaction.
347
- # @return [Server, nil] This will be nil for interactions that occur in DM channels or servers where the bot
348
- # does not have the `bot` scope.
349
- def server
350
- @bot.server(@server_id)
351
- end
352
-
353
- # Get the button component that triggered the interaction.
354
- # @return [Components::Button, nil] The button that triggered this interaction if applicable, otherwise `nil`.
355
- def button
356
- @type == TYPES[:component] ? get_component(@data['custom_id']) : nil
357
- end
358
-
359
- # Get the text input components associated with the interaction.
360
- # @return [Array<TextInput>] The text input components associated with this interaction.
361
- def text_inputs
362
- @components.filter_map do |entity|
363
- entity.component if entity.is_a?(Components::Label) && entity.component.is_a?(Components::TextInput)
364
- end
365
- end
366
-
367
- # Get a component by its custom ID.
368
- # @param custom_id [String] the custom ID of the component to find.
369
- # @return [TextInput, Button, SelectMenu, Checkbox, ModalActionGroup, nil] The component associated with the custom ID, or `nil`.
370
- def get_component(custom_id)
371
- components = flatten_components((@message&.components || []) + @components)
372
- components.find { |component| component.respond_to?(:custom_id) && component.custom_id == custom_id }
373
- end
374
-
375
- # @return [true, false] whether the application was installed by the user who initiated this interaction.
376
- def user_integration?
377
- @integration_owners[1] == @user.id
378
- end
379
-
380
- # @return [true, false] whether the application was installed by the server where this interaction originates from.
381
- def server_integration?
382
- @server_id ? @integration_owners[0] == @server_id : false
383
- end
384
-
385
- private
386
-
387
- # Set builder defaults from parameters
388
- # @param builder [OnyxCord::Webhooks::Builder]
389
- # @param content [String, nil]
390
- # @param embeds [Array<Hash, OnyxCord::Webhooks::Embed>, nil]
391
- # @param allowed_mentions [AllowedMentions, Hash, nil]
392
- # @param poll [Poll, Poll::Builder, Hash, nil]
393
- def prepare_builder(builder, content, embeds, allowed_mentions, poll)
394
- builder.poll = poll
395
- builder.content = content unless content == OnyxCord::MessagePayload::KEEP
396
- builder.allowed_mentions = allowed_mentions
397
- embeds&.each { |embed| builder << embed } unless embeds == OnyxCord::MessagePayload::KEEP
398
- end
399
-
400
- def edit_content(content, data)
401
- content == OnyxCord::MessagePayload::KEEP ? OnyxCord::MessagePayload::KEEP : data[:content]
402
- end
403
-
404
- def edit_embeds(embeds, data)
405
- embeds == OnyxCord::MessagePayload::KEEP ? OnyxCord::MessagePayload::KEEP : data[:embeds]
406
- end
407
-
408
- # @!visibility private
409
- def flatten_components(components)
410
- components = components.flat_map do |entity|
411
- case entity
412
- when Components::ActionRow
413
- entity.components
414
- when Components::Label
415
- entity.component
416
- when Components::Section
417
- entity.accessory if entity.accessory.respond_to?(:custom_id)
418
- when Components::Container
419
- flatten_components(entity.components)
420
- else
421
- entity if entity.respond_to?(:custom_id)
422
- end
423
- end
424
-
425
- components.compact
426
- end
427
- end
428
-
429
- # An ApplicationCommand for slash commands.
430
- class ApplicationCommand
431
- # Command types. `chat_input` is a command that appears in the text input field. `user` and `message` types appear as context menus
432
- # for the respective resource.
433
- TYPES = {
434
- chat_input: 1,
435
- user: 2,
436
- message: 3
437
- }.freeze
438
-
439
- # @return [Integer]
440
- attr_reader :application_id
441
-
442
- # @return [Integer, nil]
443
- attr_reader :server_id
444
-
445
- # @return [String]
446
- attr_reader :name
447
-
448
- # @return [String]
449
- attr_reader :description
450
-
451
- # @return [true, false]
452
- attr_reader :default_permission
453
-
454
- # @return [Hash]
455
- attr_reader :options
456
-
457
- # @return [Integer]
458
- attr_reader :id
459
-
460
- # @return [true, false]
461
- attr_reader :nsfw
462
-
463
- # @return [Array<Integer>]
464
- attr_reader :contexts
465
-
466
- # @return [Array<Integer>]
467
- attr_reader :integration_types
468
-
469
- # @!visibility private
470
- def initialize(data, bot, server_id = nil)
471
- @bot = bot
472
- @id = data['id'].to_i
473
- @application_id = data['application_id'].to_i
474
- @server_id = server_id&.to_i
475
-
476
- @name = data['name']
477
- @description = data['description']
478
- @default_permission = data['default_permission']
479
- @options = data['options']
480
- @nsfw = data['nsfw'] || false
481
- @contexts = data['contexts'] || []
482
- @integration_types = data['integration_types'] || []
483
- end
484
-
485
- # @param subcommand [String, nil] The subcommand to mention.
486
- # @param subcommand_group [String, nil] The subcommand group to mention.
487
- # @return [String] the layout to mention it in a message
488
- def mention(subcommand_group: nil, subcommand: nil)
489
- if subcommand_group && subcommand
490
- "</#{name} #{subcommand_group} #{subcommand}:#{id}>"
491
- elsif subcommand_group
492
- "</#{name} #{subcommand_group}:#{id}>"
493
- elsif subcommand
494
- "</#{name} #{subcommand}:#{id}>"
495
- else
496
- "</#{name}:#{id}>"
497
- end
498
- end
499
-
500
- alias_method :to_s, :mention
501
-
502
- # @param name [String] The name to use for this command.
503
- # @param description [String] The description of this command.
504
- # @param default_permission [true, false] Whether this command is available with default permissions.
505
- # @param nsfw [true, false] Whether this command should be marked as age-restricted.
506
- # @yieldparam (see Bot#edit_application_command)
507
- # @return (see Bot#edit_application_command)
508
- def edit(name: nil, description: nil, default_permission: nil, nsfw: nil, &block)
509
- @bot.edit_application_command(@id, server_id: @server_id, name: name, description: description, default_permission: default_permission, nsfw: nsfw, &block)
510
- end
511
-
512
- # Delete this application command.
513
- # @return (see Bot#delete_application_command)
514
- def delete
515
- @bot.delete_application_command(@id, server_id: @server_id)
516
- end
517
-
518
- # Get the permission configuration for this application command in a specific server.
519
- # @param server_id [Integer, String, nil] The ID of the server to fetch command permissions for.
520
- # @return [Array<Permission>] the permissions for this application command in the given server.
521
- def permissions(server_id: nil)
522
- raise ArgumentError, 'A server ID must be provided for global application commands' if @server_id.nil? && server_id.nil?
523
-
524
- response = JSON.parse(API::Application.get_application_command_permissions(@bot.token, @bot.profile.id, @server_id || server_id&.resolve_id, @id))
525
- response['permissions'].map { |permission| Permission.new(permission, response, @bot) }
526
- rescue OnyxCord::Errors::UnknownError
527
- # If there aren't any explicit overwrites configured for the command, the response is a 400.
528
- []
529
- end
530
-
531
- # An application command permission for a channel, member, or a role.
532
- class Permission
533
- # Map of permission types.
534
- TYPES = {
535
- role: 1,
536
- member: 2,
537
- channel: 3
538
- }.freeze
539
-
540
- # @return [Integer] the type of this permission.
541
- # @see TYPES
542
- attr_reader :type
543
-
544
- # @return [Integer] the ID of the entity this permission is for.
545
- attr_reader :target_id
546
-
547
- # @return [Integer] the ID of the server this permission is for.
548
- attr_reader :server_id
549
-
550
- # @!visibility private
551
- def initialize(data, command, bot)
552
- @bot = bot
553
- @type = data['type']
554
- @target_id = data['id'].to_i
555
- @overwrite = data['permission']
556
- @command_id = command['id'].to_i
557
- @server_id = command['guild_id'].to_i
558
- @application_id = command['application_id'].to_i
559
- end
560
-
561
- # Whether this permission has been allowed, e.g has a green check in the UI.
562
- # @return [true, false]
563
- def allowed?
564
- @overwrite == true
565
- end
566
-
567
- # Whether this permission has been denied, e.g has a red X-mark in the UI.
568
- # @return [true, false]
569
- def denied?
570
- @overwrite == false
571
- end
572
-
573
- # Whether this permission is applied to the everyone role in the server.
574
- # @return [true, false]
575
- def everyone?
576
- @target_id == @server_id
577
- end
578
-
579
- # Get the ID of the application command this permission is for.
580
- # @return [Integer, nil] This will be `nil` if the permission is the
581
- # default permission.
582
- def command_id
583
- @command_id unless default?
584
- end
585
-
586
- # Whether this permission is the default for all commands that don't
587
- # contain explicit permission oerwrites.
588
- # @return [true, false]
589
- def default?
590
- @command_id == @application_id
591
- end
592
-
593
- # Whether this permission is applied to every channel in the server.
594
- # @return [true, false]
595
- def all_channels?
596
- @target_id == (@server_id - 1)
597
- end
598
-
599
- # Get the user, role, or channel(s) that this permission targets.
600
- # @return [Array<Channel>, Role, Member]
601
- def target
602
- case @type
603
- when TYPES[:role]
604
- @bot.server(@server_id).role(@target_id)
605
- when TYPES[:member]
606
- @bot.server(@server_id).member(@target_id)
607
- when TYPES[:channel]
608
- all_channels? ? @bot.server(@server_id).channels : [@bot.channel(@target_id)]
609
- end
610
- end
611
-
612
- alias_method :targets, :target
613
-
614
- # @!method role?
615
- # @return [true, false] whether this permission is for a role.
616
- # @!method member?
617
- # @return [true, false] whether this permission is for a member.
618
- # @!method channel?
619
- # @return [true, false] whether this permission is for a channel.
620
- TYPES.each do |name, value|
621
- define_method("#{name}?") do
622
- @type == value
623
- end
624
- end
625
- end
626
- end
627
-
628
- # Objects specific to Interactions.
629
- module Interactions
630
- # A builder for defining slash commands options.
631
- class OptionBuilder
632
- # @!visibility private
633
- TYPES = {
634
- subcommand: 1,
635
- subcommand_group: 2,
636
- string: 3,
637
- integer: 4,
638
- boolean: 5,
639
- user: 6,
640
- channel: 7,
641
- role: 8,
642
- mentionable: 9,
643
- number: 10,
644
- attachment: 11
645
- }.freeze
646
-
647
- # Channel types that can be provided to #channel
648
- CHANNEL_TYPES = {
649
- text: 0,
650
- dm: 1,
651
- voice: 2,
652
- group_dm: 3,
653
- category: 4,
654
- news: 5,
655
- store: 6,
656
- news_thread: 10,
657
- public_thread: 11,
658
- private_thread: 12,
659
- stage: 13
660
- }.freeze
661
-
662
- # @return [Array<Hash>]
663
- attr_reader :options
664
-
665
- # @!visibility private
666
- def initialize
667
- @options = []
668
- end
669
-
670
- # @param name [String, Symbol] The name of the subcommand.
671
- # @param description [String] A description of the subcommand.
672
- # @yieldparam [OptionBuilder]
673
- # @return (see #option)
674
- # @example
675
- # bot.register_application_command(:test, 'Test command') do |cmd|
676
- # cmd.subcommand(:echo) do |sub|
677
- # sub.string('message', 'What to echo back', required: true)
678
- # end
679
- # end
680
- def subcommand(name, description)
681
- builder = OptionBuilder.new
682
- yield builder if block_given?
683
-
684
- option(TYPES[:subcommand], name, description, options: builder.to_a)
685
- end
686
-
687
- # @param name [String, Symbol] The name of the subcommand group.
688
- # @param description [String] A description of the subcommand group.
689
- # @yieldparam [OptionBuilder]
690
- # @return (see #option)
691
- # @example
692
- # bot.register_application_command(:test, 'Test command') do |cmd|
693
- # cmd.subcommand_group(:fun) do |group|
694
- # group.subcommand(:8ball) do |sub|
695
- # sub.string(:question, 'What do you ask the mighty 8ball?')
696
- # end
697
- # end
698
- # end
699
- def subcommand_group(name, description)
700
- builder = OptionBuilder.new
701
- yield builder
702
-
703
- option(TYPES[:subcommand_group], name, description, options: builder.to_a)
704
- end
705
-
706
- # @param name [String, Symbol] The name of the argument.
707
- # @param description [String] A description of the argument.
708
- # @param required [true, false] Whether this option must be provided.
709
- # @param min_length [Integer] A minimum length for option value.
710
- # @param max_length [Integer] A maximum length for option value.
711
- # @param choices [Hash, nil] Available choices, mapped as `Name => Value`.
712
- # @param autocomplete [true, false] Whether this option can dynamically show choices.
713
- # @return (see #option)
714
- def string(name, description, required: nil, min_length: nil, max_length: nil, choices: nil, autocomplete: nil)
715
- option(TYPES[:string], name, description,
716
- required: required, min_length: min_length, max_length: max_length, choices: choices, autocomplete: autocomplete)
717
- end
718
-
719
- # @param name [String, Symbol] The name of the argument.
720
- # @param description [String] A description of the argument.
721
- # @param required [true, false] Whether this option must be provided.
722
- # @param min_value [Integer] A minimum value for option.
723
- # @param max_value [Integer] A maximum value for option.
724
- # @param choices [Hash, nil] Available choices, mapped as `Name => Value`.
725
- # @param autocomplete [true, false] Whether this option can dynamically show choices.
726
- # @return (see #option)
727
- def integer(name, description, required: nil, min_value: nil, max_value: nil, choices: nil, autocomplete: nil)
728
- option(TYPES[:integer], name, description,
729
- required: required, min_value: min_value, max_value: max_value, choices: choices, autocomplete: autocomplete)
730
- end
731
-
732
- # @param name [String, Symbol] The name of the argument.
733
- # @param description [String] A description of the argument.
734
- # @param required [true, false] Whether this option must be provided.
735
- # @return (see #option)
736
- def boolean(name, description, required: nil)
737
- option(TYPES[:boolean], name, description, required: required)
738
- end
739
-
740
- # @param name [String, Symbol] The name of the argument.
741
- # @param description [String] A description of the argument.
742
- # @param required [true, false] Whether this option must be provided.
743
- # @return (see #option)
744
- def user(name, description, required: nil)
745
- option(TYPES[:user], name, description, required: required)
746
- end
747
-
748
- # @param name [String, Symbol] The name of the argument.
749
- # @param description [String] A description of the argument.
750
- # @param required [true, false] Whether this option must be provided.
751
- # @param types [Array<Symbol, Integer>] See {CHANNEL_TYPES}
752
- # @return (see #option)
753
- def channel(name, description, required: nil, types: nil)
754
- types = types&.collect { |type| type.is_a?(Numeric) ? type : CHANNEL_TYPES[type] }
755
- option(TYPES[:channel], name, description, required: required, channel_types: types)
756
- end
757
-
758
- # @param name [String, Symbol] The name of the argument.
759
- # @param description [String] A description of the argument.
760
- # @param required [true, false] Whether this option must be provided.
761
- # @return (see #option)
762
- def role(name, description, required: nil)
763
- option(TYPES[:role], name, description, required: required)
764
- end
765
-
766
- # @param name [String, Symbol] The name of the argument.
767
- # @param description [String] A description of the argument.
768
- # @param required [true, false] Whether this option must be provided.
769
- # @return (see #option)
770
- def mentionable(name, description, required: nil)
771
- option(TYPES[:mentionable], name, description, required: required)
772
- end
773
-
774
- # @param name [String, Symbol] The name of the argument.
775
- # @param description [String] A description of the argument.
776
- # @param required [true, false] Whether this option must be provided.
777
- # @param min_value [Float] A minimum value for option.
778
- # @param max_value [Float] A maximum value for option.
779
- # @param autocomplete [true, false] Whether this option can dynamically show choices.
780
- # @return (see #option)
781
- def number(name, description, required: nil, min_value: nil, max_value: nil, choices: nil, autocomplete: nil)
782
- option(TYPES[:number], name, description,
783
- required: required, min_value: min_value, max_value: max_value, choices: choices, autocomplete: autocomplete)
784
- end
785
-
786
- # @param name [String, Symbol] The name of the argument.
787
- # @param description [String] A description of the argument.
788
- # @param required [true, false] Whether this option must be provided.
789
- # @return (see #option)
790
- def attachment(name, description, required: nil)
791
- option(TYPES[:attachment], name, description, required: required)
792
- end
793
-
794
- # @!visibility private
795
- # @param type [Integer] The argument type.
796
- # @param name [String, Symbol] The name of the argument.
797
- # @param description [String] A description of the argument.
798
- # @param required [true, false] Whether this option must be provided.
799
- # @param min_value [Integer, Float] A minimum value for integer and number options.
800
- # @param max_value [Integer, Float] A maximum value for integer and number options.
801
- # @param min_length [Integer] A minimum length for string option value.
802
- # @param max_length [Integer] A maximum length for string option value.
803
- # @param channel_types [Array<Integer>] Channel types that can be provides for channel options.
804
- # @param autocomplete [true, false] Whether this option can dynamically show options.
805
- # @return Hash
806
- def option(type, name, description, required: nil, choices: nil, options: nil, min_value: nil, max_value: nil,
807
- min_length: nil, max_length: nil, channel_types: nil, autocomplete: nil)
808
- opt = { type: type, name: name, description: description }
809
- choices = choices.map { |option_name, value| { name: option_name, value: value } } if choices
810
-
811
- opt.merge!({ required: required, choices: choices, options: options, min_value: min_value,
812
- max_value: max_value, min_length: min_length, max_length: max_length,
813
- channel_types: channel_types, autocomplete: autocomplete }.compact)
814
-
815
- @options << opt
816
- opt
817
- end
818
-
819
- # @return [Array<Hash>]
820
- def to_a
821
- @options
822
- end
823
- end
824
-
825
- # Builder for creating server application command permissions.
826
- # @deprecated This system is being replaced in the near future.
827
- class PermissionBuilder
828
- # Role permission type
829
- ROLE = 1
830
- # User permission type
831
- USER = 2
832
-
833
- # @!visibility hidden
834
- def initialize
835
- @permissions = []
836
- end
837
-
838
- # Allow a role to use this command.
839
- # @param role_id [Integer]
840
- # @return [PermissionBuilder]
841
- def allow_role(role_id)
842
- create_entry(role_id, ROLE, true)
843
- end
844
-
845
- # Deny a role usage of this command.
846
- # @param role_id [Integer]
847
- # @return [PermissionBuilder]
848
- def deny_role(role_id)
849
- create_entry(role_id, ROLE, false)
850
- end
851
-
852
- # Allow a user to use this command.
853
- # @param user_id [Integer]
854
- # @return [PermissionBuilder]
855
- def allow_user(user_id)
856
- create_entry(user_id, USER, true)
857
- end
858
-
859
- # Deny a user usage of this command.
860
- # @param user_id [Integer]
861
- # @return [PermissionBuilder]
862
- def deny_user(user_id)
863
- create_entry(user_id, USER, false)
864
- end
865
-
866
- # Allow an entity to use this command.
867
- # @param object [Role, User, Member]
868
- # @return [PermissionBuilder]
869
- # @raise [ArgumentError]
870
- def allow(object)
871
- case object
872
- when OnyxCord::User, OnyxCord::Member
873
- create_entry(object.id, USER, true)
874
- when OnyxCord::Role
875
- create_entry(object.id, ROLE, true)
876
- else
877
- raise ArgumentError, "Unable to create permission for unknown type: #{object.class}"
878
- end
879
- end
880
-
881
- # Deny an entity usage of this command.
882
- # @param object [Role, User, Member]
883
- # @return [PermissionBuilder]
884
- # @raise [ArgumentError]
885
- def deny(object)
886
- case object
887
- when OnyxCord::User, OnyxCord::Member
888
- create_entry(object.id, USER, false)
889
- when OnyxCord::Role
890
- create_entry(object.id, ROLE, false)
891
- else
892
- raise ArgumentError, "Unable to create permission for unknown type: #{object.class}"
893
- end
894
- end
895
-
896
- # @!visibility private
897
- # @return [Array<Hash>]
898
- def to_a
899
- @permissions
900
- end
901
-
902
- private
903
-
904
- def create_entry(id, type, permission)
905
- @permissions << { id: id, type: type, permission: permission }
906
- self
907
- end
908
- end
909
-
910
- # A message partial for interactions.
911
- class Message
912
- include IDObject
913
-
914
- # @return [Interaction] The interaction that created this message.
915
- attr_reader :interaction
916
-
917
- # @return [String, nil] The content of the message.
918
- attr_reader :content
919
-
920
- # @return [true, false] Whether this message is pinned in the channel it belongs to.
921
- attr_reader :pinned
922
-
923
- # @return [true, false]
924
- attr_reader :tts
925
-
926
- # @return [Time]
927
- attr_reader :timestamp
928
-
929
- # @return [Time, nil]
930
- attr_reader :edited_timestamp
931
-
932
- # @return [true, false]
933
- attr_reader :edited
934
-
935
- # @return [Integer]
936
- attr_reader :id
937
-
938
- # @return [User] The user of the application.
939
- attr_reader :author
940
-
941
- # @return [Attachment]
942
- attr_reader :attachments
943
-
944
- # @return [Array<Embed>]
945
- attr_reader :embeds
946
-
947
- # @return [Array<User>]
948
- attr_reader :mentions
949
-
950
- # @return [Integer]
951
- attr_reader :flags
952
-
953
- # @return [Integer]
954
- attr_reader :channel_id
955
-
956
- # @return [Hash, nil]
957
- attr_reader :message_reference
958
-
959
- # @return [Array<Component>]
960
- attr_reader :components
961
-
962
- # @!visibility private
963
- def initialize(data, bot, interaction)
964
- @data = data
965
- @bot = bot
966
- @interaction = interaction
967
- @content = data['content']
968
- @channel_id = data['channel_id'].to_i
969
- @pinned = data['pinned']
970
- @tts = data['tts']
971
-
972
- @message_reference = data['message_reference']
973
-
974
- @server_id = @interaction.server_id
975
-
976
- @timestamp = Time.parse(data['timestamp']) if data['timestamp']
977
- @edited_timestamp = data['edited_timestamp'].nil? ? nil : Time.parse(data['edited_timestamp'])
978
- @edited = !@edited_timestamp.nil?
979
-
980
- @id = data['id'].to_i
981
-
982
- @author = bot.ensure_user(data['author'] || data['member']['user'])
983
-
984
- @attachments = []
985
- @attachments = data['attachments'].map { |e| Attachment.new(e, self, @bot) } if data['attachments']
986
-
987
- @embeds = []
988
- @embeds = data['embeds'].map { |e| Embed.new(e, self) } if data['embeds']
989
-
990
- @mentions = []
991
-
992
- data['mentions']&.each do |element|
993
- @mentions << bot.ensure_user(element)
994
- end
995
-
996
- @mention_roles = data['mention_roles']
997
- @mention_everyone = data['mention_everyone']
998
- @flags = data['flags']
999
- @pinned = data['pinned']
1000
- @components = data['components']&.filter_map { |component| Components.from_data(component, @bot) } || []
1001
- end
1002
-
1003
- # @return [Member, nil] This will return nil if the bot does not have access to the
1004
- # server the interaction originated in.
1005
- def member
1006
- server&.member(@user.id)
1007
- end
1008
-
1009
- # @return [Server, nil] This will return nil if the bot does not have access to the
1010
- # server the interaction originated in.
1011
- def server
1012
- @bot.server(@server_id)
1013
- end
1014
-
1015
- # @return [Channel] The channel the interaction originates from.
1016
- # @raise [Errors::NoPermission] When the bot is not in the server associated with this interaction.
1017
- def channel
1018
- @bot.channel(@channel_id)
1019
- end
1020
-
1021
- # Respond to this message.
1022
- # @param (see Interaction#send_message)
1023
- # @yieldparam (see Interaction#send_message)
1024
- def respond(content: nil, embeds: nil, allowed_mentions: nil, flags: 0, ephemeral: true, components: nil, attachments: nil, &block)
1025
- @interaction.send_message(content: content, embeds: embeds, allowed_mentions: allowed_mentions, flags: flags, ephemeral: ephemeral, components: components, attachments: attachments, &block)
1026
- end
1027
-
1028
- # Delete this message.
1029
- def delete
1030
- @interaction.delete_message(@id)
1031
- end
1032
-
1033
- # Edit this message's data.
1034
- # @param content (see Interaction#send_message)
1035
- # @param embeds (see Interaction#send_message)
1036
- # @param allowed_mentions (see Interaction#send_message)
1037
- # @yieldparam (see Interaction#send_message)
1038
- def edit(content: nil, embeds: nil, allowed_mentions: nil, components: nil, attachments: nil, &block)
1039
- @interaction.edit_message(@id, content: content, embeds: embeds, allowed_mentions: allowed_mentions, components: components, attachments: attachments, &block)
1040
- end
1041
-
1042
- # @return [OnyxCord::Message]
1043
- def to_message
1044
- OnyxCord::Message.new(@data, @bot)
1045
- end
1046
-
1047
- alias_method :message, :to_message
1048
-
1049
- # @!visibility private
1050
- def inspect
1051
- "<Interaction::Message content=#{@content.inspect} embeds=#{@embeds.inspect} channel_id=#{@channel_id} server_id=#{@server_id} author=#{@author.inspect}>"
1052
- end
1053
- end
1054
-
1055
- # Supplemental metadata about an interaction.
1056
- class Metadata
1057
- include IDObject
1058
-
1059
- # @return [Integer] the type of the interaction.
1060
- attr_reader :type
1061
-
1062
- # @return [User] the user that initiated the interaction.
1063
- attr_reader :user
1064
-
1065
- # @return [User, nil] the user that the command was ran on.
1066
- attr_reader :target_user
1067
-
1068
- # @return [Integer, nil] the ID of the message the command was ran on.
1069
- attr_reader :target_message_id
1070
-
1071
- # @return [Metadata, nil] the metadata for the interaction that opened the modal.
1072
- attr_reader :triggering_metadata
1073
-
1074
- # @return [Integer, nil] the ID of the message that contained the interactive message component.
1075
- attr_reader :interacted_message_id
1076
-
1077
- # @return [Integer, nil] the ID the original response message; only present on follow-up messages.
1078
- attr_reader :original_response_message_id
1079
-
1080
- # @!visibility private
1081
- def initialize(data, message, bot)
1082
- @bot = bot
1083
- @message = message
1084
- @id = data['id'].to_i
1085
- @type = data['type']
1086
- @user = bot.ensure_user(data['user']) if data['user']
1087
- @target_user = bot.ensure_user(data['target_user']) if data['target_user']
1088
- @target_message_id = data['target_message_id']&.to_i
1089
- @triggering_metadata = Metadata.new(data['triggering_interaction_metadata'], @message, @bot) if data['triggering_interaction_metadata']
1090
- @interacted_message_id = data['interacted_message_id']&.to_i
1091
- @original_response_message_id = data['original_response_message_id']&.to_i
1092
- @integration_owners = data['authorizing_integration_owners']&.to_h { |key, value| [key.to_i, value.to_i] }
1093
- end
1094
-
1095
- # Check if the interaction was triggered by a user by installed the application.
1096
- # @return [true, false] whether or not the application was installed by the user
1097
- # who initiated this interaction.
1098
- def user_integration?
1099
- @integration_owners[1] == @user.id
1100
- end
1101
-
1102
- # Check if the interaction was triggered by a server by installed the application.
1103
- # @return [true, false] whether or not the application was installed by the server
1104
- # where this interaction originates from.
1105
- def server_integration?
1106
- @integration_owners[0] == @message.server.id
1107
- end
1108
-
1109
- # Attempt to fetch the target message of the interaction.
1110
- # @return [Message, nil] the target message of the interaction, or `nil` if it couldn't be found.
1111
- def target_message
1112
- return unless @target_message_id
1113
-
1114
- @target_message ||= @message.channel.message(@target_message_id)
1115
- end
1116
-
1117
- # Attempt to fetch the message that contained the interatctive component.
1118
- # @return [Message, nil] the interacted message with the component, or `nil` if it couldn't be found.
1119
- def interacted_message
1120
- return unless @interacted_message_id
1121
-
1122
- @interacted_message ||= @message.channel.message(@interacted_message_id)
1123
- end
1124
-
1125
- # Attempt to fetch the original response message of the interaction.
1126
- # @return [Message, nil] the original response message of the interaction, or `nil` if it couldn't be found.
1127
- def original_response_message
1128
- return unless @original_response_message_id
1129
-
1130
- @original_response_message ||= @message.channel.message(@original_response_message_id)
1131
- end
1132
-
1133
- # @!method command?
1134
- # @return [true, false] whether or not the interaction metadata is for an application command.
1135
- # @!method component?
1136
- # @return [true, false] whether or not the interaction metadata is for a message component.
1137
- # @!method modal_submit?
1138
- # @return [true, false] whether or not the interaction metadata is for a modal submission.
1139
- Interaction::TYPES.each do |name, value|
1140
- define_method("#{name}?") do
1141
- @type == value
1142
- end
1143
- end
1144
-
1145
- # @!visibility private
1146
- def inspect
1147
- "<Interactions::Metadata id=#{@id} type=#{@type} user=#{@user.inspect} target_user=#{@target_user.inspect}>"
1148
- end
1149
- end
1150
- end
1151
- end