onyxcord 2.0.13 → 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/{errors.rb → core/errors.rb} +18 -3
  27. data/lib/onyxcord/{logger.rb → core/logger.rb} +5 -0
  28. data/lib/onyxcord/core/version.rb +5 -0
  29. data/lib/onyxcord/events/await/base.rb +48 -0
  30. data/lib/onyxcord/events/await.rb +1 -46
  31. data/lib/onyxcord/events/ban/base.rb +54 -0
  32. data/lib/onyxcord/events/ban/remove.rb +11 -0
  33. data/lib/onyxcord/events/bans.rb +2 -58
  34. data/lib/onyxcord/events/channels/base.rb +91 -0
  35. data/lib/onyxcord/events/channels/delete.rb +73 -0
  36. data/lib/onyxcord/events/channels/pins.rb +44 -0
  37. data/lib/onyxcord/events/channels/recipients.rb +77 -0
  38. data/lib/onyxcord/events/channels.rb +4 -239
  39. data/lib/onyxcord/events/guilds/audit_logs.rb +79 -0
  40. data/lib/onyxcord/events/guilds/base.rb +97 -0
  41. data/lib/onyxcord/events/guilds/emoji.rb +147 -0
  42. data/lib/onyxcord/events/guilds.rb +3 -267
  43. data/lib/onyxcord/events/handlers/channels.rb +133 -0
  44. data/lib/onyxcord/events/handlers/core.rb +146 -0
  45. data/lib/onyxcord/events/handlers/guilds.rb +375 -0
  46. data/lib/onyxcord/events/handlers/interactions.rb +238 -0
  47. data/lib/onyxcord/events/handlers/lifetime.rb +71 -0
  48. data/lib/onyxcord/events/handlers/messages.rb +218 -0
  49. data/lib/onyxcord/events/handlers/presence.rb +56 -0
  50. data/lib/onyxcord/events/handlers/raw.rb +39 -0
  51. data/lib/onyxcord/events/handlers/reactions.rb +98 -0
  52. data/lib/onyxcord/events/handlers/scheduled_events.rb +243 -0
  53. data/lib/onyxcord/events/handlers/voice.rb +46 -0
  54. data/lib/onyxcord/events/integration/base.rb +45 -0
  55. data/lib/onyxcord/events/integration/create.rb +11 -0
  56. data/lib/onyxcord/events/integration/delete.rb +48 -0
  57. data/lib/onyxcord/events/integration/update.rb +11 -0
  58. data/lib/onyxcord/events/integrations.rb +4 -98
  59. data/lib/onyxcord/events/interactions/application_commands.rb +185 -0
  60. data/lib/onyxcord/events/interactions/autocomplete.rb +62 -0
  61. data/lib/onyxcord/events/interactions/base.rb +175 -0
  62. data/lib/onyxcord/events/interactions/components.rb +221 -0
  63. data/lib/onyxcord/events/interactions/permissions.rb +53 -0
  64. data/lib/onyxcord/events/interactions.rb +5 -622
  65. data/lib/onyxcord/events/invite/create.rb +79 -0
  66. data/lib/onyxcord/events/invite/delete.rb +55 -0
  67. data/lib/onyxcord/events/invites.rb +2 -125
  68. data/lib/onyxcord/events/lifetime/base.rb +31 -0
  69. data/lib/onyxcord/events/lifetime.rb +1 -29
  70. data/lib/onyxcord/events/member/add.rb +12 -0
  71. data/lib/onyxcord/events/member/base.rb +67 -0
  72. data/lib/onyxcord/events/member/delete.rb +21 -0
  73. data/lib/onyxcord/events/member/update.rb +25 -0
  74. data/lib/onyxcord/events/members.rb +4 -108
  75. data/lib/onyxcord/events/message/base.rb +295 -0
  76. data/lib/onyxcord/events/message/ids.rb +71 -0
  77. data/lib/onyxcord/events/message/mentions.rb +55 -0
  78. data/lib/onyxcord/events/message/updates.rb +27 -0
  79. data/lib/onyxcord/events/message.rb +4 -397
  80. data/lib/onyxcord/events/poll/add.rb +11 -0
  81. data/lib/onyxcord/events/poll/base.rb +106 -0
  82. data/lib/onyxcord/events/poll/remove.rb +11 -0
  83. data/lib/onyxcord/events/polls.rb +3 -116
  84. data/lib/onyxcord/events/presence/playing.rb +77 -0
  85. data/lib/onyxcord/events/presence/status.rb +60 -0
  86. data/lib/onyxcord/events/presence.rb +2 -129
  87. data/lib/onyxcord/events/raw/base.rb +74 -0
  88. data/lib/onyxcord/events/raw.rb +1 -72
  89. data/lib/onyxcord/events/reactions/base.rb +143 -0
  90. data/lib/onyxcord/events/reactions/clear.rb +99 -0
  91. data/lib/onyxcord/events/reactions.rb +2 -216
  92. data/lib/onyxcord/events/role/create.rb +46 -0
  93. data/lib/onyxcord/events/role/delete.rb +40 -0
  94. data/lib/onyxcord/events/role/update.rb +11 -0
  95. data/lib/onyxcord/events/roles.rb +3 -85
  96. data/lib/onyxcord/events/scheduled_events/events.rb +112 -0
  97. data/lib/onyxcord/events/scheduled_events/users.rb +91 -0
  98. data/lib/onyxcord/events/scheduled_events.rb +2 -169
  99. data/lib/onyxcord/events/thread/base.rb +49 -0
  100. data/lib/onyxcord/events/thread/members.rb +44 -0
  101. data/lib/onyxcord/events/thread/update.rb +18 -0
  102. data/lib/onyxcord/events/threads.rb +3 -98
  103. data/lib/onyxcord/events/typing/base.rb +73 -0
  104. data/lib/onyxcord/events/typing.rb +1 -71
  105. data/lib/onyxcord/events/voice/server_update.rb +48 -0
  106. data/lib/onyxcord/events/voice/state_update.rb +137 -0
  107. data/lib/onyxcord/events/voice_server_update.rb +2 -46
  108. data/lib/onyxcord/events/voice_state_update.rb +2 -135
  109. data/lib/onyxcord/events/webhook/update.rb +65 -0
  110. data/lib/onyxcord/events/webhooks.rb +1 -63
  111. data/lib/onyxcord/gateway/client.rb +460 -0
  112. data/lib/onyxcord/interactions/command.rb +120 -0
  113. data/lib/onyxcord/interactions/context.rb +109 -0
  114. data/lib/onyxcord/interactions/internal/application_command.rb +203 -0
  115. data/lib/onyxcord/interactions/internal/message.rb +152 -0
  116. data/lib/onyxcord/interactions/internal/metadata.rb +109 -0
  117. data/lib/onyxcord/interactions/internal/option_builder.rb +230 -0
  118. data/lib/onyxcord/interactions/internal/permission_builder.rb +90 -0
  119. data/lib/onyxcord/interactions/option.rb +88 -0
  120. data/lib/onyxcord/interactions/registry.rb +50 -0
  121. data/lib/onyxcord/interactions.rb +16 -0
  122. data/lib/onyxcord/internal/async_runtime.rb +32 -0
  123. data/lib/onyxcord/internal/event_bus.rb +591 -0
  124. data/lib/onyxcord/internal/event_executor.rb +155 -0
  125. data/lib/onyxcord/internal/gateway/opcodes.rb +22 -0
  126. data/lib/onyxcord/internal/gateway/session.rb +45 -0
  127. data/lib/onyxcord/internal/http.rb +189 -0
  128. data/lib/onyxcord/internal/json.rb +51 -0
  129. data/lib/onyxcord/internal/message_payload.rb +78 -0
  130. data/lib/onyxcord/internal/rate_limiter/async_rest.rb +151 -0
  131. data/lib/onyxcord/internal/rate_limiter/gateway.rb +44 -0
  132. data/lib/onyxcord/internal/rate_limiter/rest.rb +144 -0
  133. data/lib/onyxcord/internal/upload.rb +39 -0
  134. data/lib/onyxcord/internal/websocket.rb +79 -0
  135. data/lib/onyxcord/light/data.rb +1 -1
  136. data/lib/onyxcord/light/integrations.rb +1 -1
  137. data/lib/onyxcord/light/light_bot.rb +7 -7
  138. data/lib/onyxcord/{data → models}/activity.rb +2 -2
  139. data/lib/onyxcord/{data → models}/application.rb +3 -3
  140. data/lib/onyxcord/{data → models}/avatar_decoration.rb +1 -1
  141. data/lib/onyxcord/{data → models}/channel.rb +23 -23
  142. data/lib/onyxcord/{data → models}/collectibles.rb +1 -1
  143. data/lib/onyxcord/{data → models}/emoji.rb +1 -1
  144. data/lib/onyxcord/models/interaction.rb +450 -0
  145. data/lib/onyxcord/{data → models}/invite.rb +1 -1
  146. data/lib/onyxcord/{data → models}/member.rb +11 -11
  147. data/lib/onyxcord/{data → models}/message.rb +22 -14
  148. data/lib/onyxcord/{data → models}/poll.rb +2 -2
  149. data/lib/onyxcord/{data → models}/primary_server.rb +1 -1
  150. data/lib/onyxcord/{data → models}/profile.rb +4 -4
  151. data/lib/onyxcord/{data → models}/role.rb +6 -12
  152. data/lib/onyxcord/{data → models}/scheduled_event.rb +5 -5
  153. data/lib/onyxcord/{data → models}/server.rb +41 -41
  154. data/lib/onyxcord/{data → models}/server_preview.rb +2 -2
  155. data/lib/onyxcord/{data → models}/team.rb +1 -1
  156. data/lib/onyxcord/{data → models}/user.rb +5 -5
  157. data/lib/onyxcord/{data → models}/webhook.rb +13 -11
  158. data/lib/onyxcord/models.rb +57 -0
  159. data/lib/onyxcord/{api.rb → rest/client.rb} +83 -27
  160. data/lib/onyxcord/{api → rest/routes}/application.rb +79 -57
  161. data/lib/onyxcord/rest/routes/channel/base.rb +73 -0
  162. data/lib/onyxcord/rest/routes/channel/groups.rb +78 -0
  163. data/lib/onyxcord/rest/routes/channel/messages.rb +130 -0
  164. data/lib/onyxcord/rest/routes/channel/permissions.rb +73 -0
  165. data/lib/onyxcord/rest/routes/channel/pins.rb +45 -0
  166. data/lib/onyxcord/rest/routes/channel/polls.rb +32 -0
  167. data/lib/onyxcord/rest/routes/channel/reactions.rb +86 -0
  168. data/lib/onyxcord/rest/routes/channel/threads.rb +176 -0
  169. data/lib/onyxcord/rest/routes/channel/webhooks.rb +47 -0
  170. data/lib/onyxcord/rest/routes/channel.rb +12 -0
  171. data/lib/onyxcord/{api/interaction.rb → rest/routes/interaction/base.rb} +10 -33
  172. data/lib/onyxcord/rest/routes/interaction/response.rb +24 -0
  173. data/lib/onyxcord/rest/routes/interaction.rb +4 -0
  174. data/lib/onyxcord/{api → rest/routes}/invite.rb +7 -7
  175. data/lib/onyxcord/rest/routes/server/admin.rb +174 -0
  176. data/lib/onyxcord/rest/routes/server/assets.rb +25 -0
  177. data/lib/onyxcord/rest/routes/server/bans.rb +67 -0
  178. data/lib/onyxcord/rest/routes/server/base.rb +77 -0
  179. data/lib/onyxcord/rest/routes/server/channels.rb +58 -0
  180. data/lib/onyxcord/rest/routes/server/emoji.rb +48 -0
  181. data/lib/onyxcord/rest/routes/server/members.rb +109 -0
  182. data/lib/onyxcord/rest/routes/server/messages.rb +19 -0
  183. data/lib/onyxcord/rest/routes/server/roles.rb +156 -0
  184. data/lib/onyxcord/rest/routes/server/scheduled_events.rb +86 -0
  185. data/lib/onyxcord/rest/routes/server.rb +12 -0
  186. data/lib/onyxcord/{api → rest/routes}/user.rb +23 -23
  187. data/lib/onyxcord/{api → rest/routes}/webhook.rb +30 -32
  188. data/lib/onyxcord/{allowed_mentions.rb → utils/allowed_mentions.rb} +9 -1
  189. data/lib/onyxcord/utils/timestamp.rb +69 -0
  190. data/lib/onyxcord/voice/{voice_bot.rb → client.rb} +4 -4
  191. data/lib/onyxcord/voice/encoder.rb +1 -1
  192. data/lib/onyxcord/voice/network/udp.rb +135 -0
  193. data/lib/onyxcord/voice/network/websocket.rb +225 -0
  194. data/lib/onyxcord/voice/network.rb +5 -357
  195. data/lib/onyxcord/webhooks/builder.rb +1 -1
  196. data/lib/onyxcord/webhooks/client.rb +13 -13
  197. data/lib/onyxcord/webhooks/modal/group_builder.rb +55 -0
  198. data/lib/onyxcord/webhooks/modal/label_builder.rb +183 -0
  199. data/lib/onyxcord/webhooks/modal.rb +2 -239
  200. data/lib/onyxcord/webhooks/version.rb +3 -3
  201. data/lib/onyxcord/webhooks/view/container_builder.rb +80 -0
  202. data/lib/onyxcord/webhooks/view/file_builder.rb +24 -0
  203. data/lib/onyxcord/webhooks/view/media_gallery_builder.rb +50 -0
  204. data/lib/onyxcord/webhooks/view/row_builder.rb +120 -0
  205. data/lib/onyxcord/webhooks/view/section_builder.rb +61 -0
  206. data/lib/onyxcord/webhooks/view/select_menu_builder.rb +77 -0
  207. data/lib/onyxcord/webhooks/view/separator_builder.rb +22 -0
  208. data/lib/onyxcord/webhooks/view/text_display_builder.rb +20 -0
  209. data/lib/onyxcord/webhooks/view.rb +9 -425
  210. data/lib/onyxcord.rb +106 -40
  211. metadata +208 -91
  212. data/.github/CONTRIBUTING.md +0 -13
  213. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
  214. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -24
  215. data/.github/pull_request_template.md +0 -37
  216. data/.github/workflows/ci.yml +0 -78
  217. data/.github/workflows/codeql.yml +0 -65
  218. data/.github/workflows/deploy.yml +0 -54
  219. data/.github/workflows/release.yml +0 -51
  220. data/.gitignore +0 -17
  221. data/.markdownlint.json +0 -4
  222. data/.overcommit.yml +0 -7
  223. data/.rspec +0 -2
  224. data/.rubocop.yml +0 -129
  225. data/.yardopts +0 -1
  226. data/CHANGELOG.md +0 -202
  227. data/Gemfile +0 -6
  228. data/LICENSE.txt +0 -21
  229. data/README.md +0 -448
  230. data/Rakefile +0 -13
  231. data/lib/onyxcord/api/channel.rb +0 -705
  232. data/lib/onyxcord/api/server.rb +0 -775
  233. data/lib/onyxcord/async/runtime.rb +0 -30
  234. data/lib/onyxcord/commands/command_bot.rb +0 -505
  235. data/lib/onyxcord/data/interaction.rb +0 -1143
  236. data/lib/onyxcord/data.rb +0 -57
  237. data/lib/onyxcord/event_executor.rb +0 -153
  238. data/lib/onyxcord/gateway.rb +0 -500
  239. data/lib/onyxcord/http.rb +0 -115
  240. data/lib/onyxcord/json.rb +0 -49
  241. data/lib/onyxcord/rate_limiter/async_rest.rb +0 -149
  242. data/lib/onyxcord/rate_limiter/gateway.rb +0 -42
  243. data/lib/onyxcord/rate_limiter/rest.rb +0 -142
  244. data/lib/onyxcord/version.rb +0 -7
  245. data/lib/onyxcord/websocket.rb +0 -77
  246. data/onyxcord.gemspec +0 -63
  247. /data/lib/onyxcord/{configuration.rb → core/configuration.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
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ class OnyxCord::Commands::Bot
4
+ module Permissions
5
+ # Sets the permission level of a user
6
+ # @param id [Integer] the ID of the user whose level to set
7
+ # @param level [Integer] the level to set the permission to
8
+ def set_user_permission(id, level)
9
+ @permissions[:users][id] = level
10
+ end
11
+
12
+ # Sets the permission level of a role - this applies to all users in the role
13
+ # @param id [Integer] the ID of the role whose level to set
14
+ # @param level [Integer] the level to set the permission to
15
+
16
+ def set_role_permission(id, level)
17
+ @permissions[:roles][id] = level
18
+ end
19
+
20
+ # Check if a user has permission to do something
21
+ # @param user [User] The user to check
22
+ # @param level [Integer] The minimum permission level the user should have (inclusive)
23
+ # @param server [Server] The server on which to check
24
+ # @return [true, false] whether or not the user has the given permission
25
+
26
+ def permission?(user, level, server)
27
+ determined_level = if user.webhook? || server.nil?
28
+ 0
29
+ else
30
+ user.roles.reduce(0) do |memo, role|
31
+ [@permissions[:roles][role.id] || 0, memo].max
32
+ end
33
+ end
34
+
35
+ [@permissions[:users][user.id] || 0, determined_level].max >= level
36
+ end
37
+
38
+ # @see Commands::Bot#update_channels
39
+
40
+ private
41
+
42
+ def required_permissions?(member, required, channel = nil)
43
+ required.reduce(true) do |a, action|
44
+ a && !member.webhook? && !member.is_a?(OnyxCord::Recipient) && member.permission?(action, channel)
45
+ end
46
+ end
47
+
48
+ def required_roles?(member, required)
49
+ return true if member.webhook? || member.is_a?(OnyxCord::Recipient) || required.nil? || required.empty?
50
+
51
+ required.is_a?(Array) ? check_multiple_roles(member, required) : member.role?(role)
52
+ end
53
+
54
+ def allowed_roles?(member, required)
55
+ return true if member.webhook? || member.is_a?(OnyxCord::Recipient) || required.nil? || required.empty?
56
+
57
+ required.is_a?(Array) ? check_multiple_roles(member, required, false) : member.role?(role)
58
+ end
59
+
60
+ def check_multiple_roles(member, required, all_roles = true)
61
+ if all_roles
62
+ required.all? do |role|
63
+ member.role?(role)
64
+ end
65
+ else
66
+ required.any? do |role|
67
+ member.role?(role)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,209 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'onyxcord/bot'
4
+ require 'onyxcord/models'
5
+ require 'onyxcord/commands/parser'
6
+ require 'onyxcord/commands/events'
7
+ require 'onyxcord/commands/container'
8
+ require 'onyxcord/commands/rate_limiter'
9
+ require 'time'
10
+
11
+ # Specialized bot to run commands
12
+
13
+ module OnyxCord::Commands
14
+ # Bot that supports commands and command chains
15
+ class Bot < OnyxCord::Bot
16
+ # @return [Hash] this bot's attributes.
17
+ attr_reader :attributes
18
+
19
+ # @return [String, Array<String>, #call] the prefix commands are triggered with.
20
+ # @see #initialize
21
+ attr_reader :prefix
22
+
23
+ include CommandContainer
24
+ require 'onyxcord/commands/bot/execution'
25
+ include Execution
26
+ require 'onyxcord/commands/bot/permissions'
27
+ include Permissions
28
+ require 'onyxcord/commands/bot/channels'
29
+ include Channels
30
+ require 'onyxcord/commands/bot/message_dispatch'
31
+ include MessageDispatch
32
+
33
+ # Creates a new Commands::Bot and logs in to Discord.
34
+ # @param attributes [Hash] The attributes to initialize the Commands::Bot with.
35
+ # @see OnyxCord::Bot#initialize OnyxCord::Bot#initialize for other attributes that should be used to create the underlying regular bot.
36
+ # @option attributes [String, Array<String>, #call] :prefix The prefix that should trigger this bot's commands. It
37
+ # can be:
38
+ #
39
+ # * Any string (including the empty string). This has the effect that if a message starts with the prefix, the
40
+ # prefix will be stripped and the rest of the chain will be parsed as a command chain. Note that it will be
41
+ # literal - if the prefix is "hi" then the corresponding trigger string for a command called "test" would be
42
+ # "hitest". Don't forget to put spaces in if you need them!
43
+ # * An array of prefixes. Those will behave similarly to setting one string as a prefix, but instead of only one
44
+ # string, any of the strings in the array can be used.
45
+ # * Something Proc-like (responds to :call) that takes a {Message} object as an argument and returns either
46
+ # the command chain in raw form or `nil` if the given message shouldn't be parsed. This can be used to make more
47
+ # complicated dynamic prefixes (e. g. based on server), or even something else entirely (suffixes, or most
48
+ # adventurous, infixes).
49
+ # @option attributes [true, false] :advanced_functionality Whether to enable advanced functionality (very powerful
50
+ # way to nest commands into chains, see https://github.com/kruldevb/OnyxCord/wiki/Commands#command-chain-syntax
51
+ # for info. Default is false.
52
+ # @option attributes [Symbol, Array<Symbol>, false] :help_command The name of the command that displays info for
53
+ # other commands. Use an array if you want to have aliases. Default is "help". If none should be created, use
54
+ # `false` as the value.
55
+ # @option attributes [String, #call] :command_doesnt_exist_message The message that should be displayed if a user attempts
56
+ # to use a command that does not exist. If none is specified, no message will be displayed. In the message, you
57
+ # can use the string '%command%' that will be replaced with the name of the command. Anything responding to call
58
+ # such as a proc will be called with the event, and is expected to return a String or nil.
59
+ # @option attributes [String] :no_permission_message The message to be displayed when `NoPermission` error is raised.
60
+ # @option attributes [true, false] :spaces_allowed Whether spaces are allowed to occur between the prefix and the
61
+ # command. Default is false.
62
+ # @option attributes [true, false] :webhook_commands Whether messages sent by webhooks are allowed to trigger
63
+ # commands. Default is true.
64
+ # @option attributes [Array<String, Integer, Channel>] :channels The channels this command bot accepts commands on.
65
+ # Superseded if a command has a 'channels' attribute.
66
+ # @option attributes [String] :previous Character that should designate the result of the previous command in
67
+ # a command chain (see :advanced_functionality). Default is '~'. Set to an empty string to disable.
68
+ # @option attributes [String] :chain_delimiter Character that should designate that a new command begins in the
69
+ # command chain (see :advanced_functionality). Default is '>'. Set to an empty string to disable.
70
+ # @option attributes [String] :chain_args_delim Character that should separate the command chain arguments from the
71
+ # chain itself (see :advanced_functionality). Default is ':'. Set to an empty string to disable.
72
+ # @option attributes [String] :sub_chain_start Character that should start a sub-chain (see
73
+ # :advanced_functionality). Default is '['. Set to an empty string to disable.
74
+ # @option attributes [String] :sub_chain_end Character that should end a sub-chain (see
75
+ # :advanced_functionality). Default is ']'. Set to an empty string to disable.
76
+ # @option attributes [String] :quote_start Character that should start a quoted string (see
77
+ # :advanced_functionality). Default is '"'. Set to an empty string to disable.
78
+ # @option attributes [String] :quote_end Character that should end a quoted string (see
79
+ # :advanced_functionality). Default is '"' or the same as :quote_start. Set to an empty string to disable.
80
+ # @option attributes [true, false] :ignore_bots Whether the bot should ignore bot accounts or not. Default is false.
81
+ def initialize(**attributes)
82
+ # TODO: This needs to be revisited. undefined attributes are treated
83
+ # as explicitly passed nils.
84
+ super(
85
+ log_mode: attributes[:log_mode],
86
+ token: attributes[:token],
87
+ client_id: attributes[:client_id],
88
+ type: attributes[:type],
89
+ name: attributes[:name],
90
+ fancy_log: attributes[:fancy_log],
91
+ suppress_ready: attributes[:suppress_ready],
92
+ parse_self: attributes[:parse_self],
93
+ shard_id: attributes[:shard_id],
94
+ num_shards: attributes[:num_shards],
95
+ redact_token: attributes.key?(:redact_token) ? attributes[:redact_token] : true,
96
+ ignore_bots: attributes[:ignore_bots],
97
+ compress_mode: attributes[:compress_mode],
98
+ intents: attributes[:intents] || :all
99
+ )
100
+
101
+ @prefix = attributes[:prefix]
102
+ @attributes = {
103
+ # Whether advanced functionality such as command chains are enabled
104
+ advanced_functionality: attributes[:advanced_functionality].nil? ? false : attributes[:advanced_functionality],
105
+
106
+ # The name of the help command (that displays information to other commands). False if none should exist
107
+ help_command: attributes[:help_command].is_a?(FalseClass) ? nil : (attributes[:help_command] || :help),
108
+
109
+ # The message to display for when a command doesn't exist, %command% to get the command name in question and nil for no message
110
+ # No default value here because it may not be desired behaviour
111
+ command_doesnt_exist_message: attributes[:command_doesnt_exist_message],
112
+
113
+ # The message to be displayed when `NoPermission` error is raised.
114
+ no_permission_message: attributes[:no_permission_message],
115
+
116
+ # Spaces allowed between prefix and command
117
+ spaces_allowed: attributes[:spaces_allowed].nil? ? false : attributes[:spaces_allowed],
118
+
119
+ # Webhooks allowed to trigger commands
120
+ webhook_commands: attributes[:webhook_commands].nil? || attributes[:webhook_commands],
121
+
122
+ channels: attributes[:channels] || [],
123
+
124
+ # All of the following need to be one character
125
+ # String to designate previous result in command chain
126
+ previous: attributes[:previous] || '~',
127
+
128
+ # Command chain delimiter
129
+ chain_delimiter: attributes[:chain_delimiter] || '>',
130
+
131
+ # Chain argument delimiter
132
+ chain_args_delim: attributes[:chain_args_delim] || ':',
133
+
134
+ # Sub-chain starting character
135
+ sub_chain_start: attributes[:sub_chain_start] || '[',
136
+
137
+ # Sub-chain ending character
138
+ sub_chain_end: attributes[:sub_chain_end] || ']',
139
+
140
+ # Quoted mode starting character
141
+ quote_start: attributes[:quote_start] || '"',
142
+
143
+ # Quoted mode ending character
144
+ quote_end: attributes[:quote_end] || attributes[:quote_start] || '"',
145
+
146
+ # Default block for handling internal exceptions, or a string to respond with
147
+ rescue: attributes[:rescue]
148
+ }
149
+
150
+ @permissions = {
151
+ roles: {},
152
+ users: {}
153
+ }
154
+
155
+ return unless @attributes[:help_command]
156
+
157
+ command(@attributes[:help_command], max_args: 1, description: 'Shows a list of all the commands available or displays help for a specific command.', usage: 'help [command name]') do |event, command_name|
158
+ if command_name
159
+ command = @commands[command_name.to_sym]
160
+ if command.is_a?(CommandAlias)
161
+ command = command.aliased_command
162
+ command_name = command.name
163
+ end
164
+ # rubocop:disable Lint/ReturnInVoidContext
165
+ return "The command `#{command_name}` does not exist!" unless command
166
+ # rubocop:enable Lint/ReturnInVoidContext
167
+
168
+ desc = command.attributes[:description] || '*No description available*'
169
+ usage = command.attributes[:usage]
170
+ parameters = command.attributes[:parameters]
171
+ result = "**`#{command_name}`**: #{desc}"
172
+ aliases = command_aliases(command_name.to_sym)
173
+ unless aliases.empty?
174
+ result += "\nAliases: "
175
+ result += aliases.map { |a| "`#{a.name}`" }.join(', ')
176
+ end
177
+ result += "\nUsage: `#{usage}`" if usage
178
+ if parameters
179
+ result += "\nAccepted Parameters:\n```"
180
+ parameters.each { |p| result += "\n#{p}" }
181
+ result += '```'
182
+ end
183
+ result
184
+ else
185
+ available_commands = @commands.values.reject do |c|
186
+ c.is_a?(CommandAlias) || !c.attributes[:help_available] || !required_roles?(event.user, c.attributes[:required_roles]) || !allowed_roles?(event.user, c.attributes[:allowed_roles]) || !required_permissions?(event.user, c.attributes[:required_permissions], event.channel)
187
+ end
188
+ case available_commands.length
189
+ when 0..5
190
+ available_commands.reduce "**List of commands:**\n" do |memo, c|
191
+ memo + "**`#{c.name}`**: #{c.attributes[:description] || '*No description available*'}\n"
192
+ end
193
+ when 5..50
194
+ (available_commands.reduce "**List of commands:**\n" do |memo, c|
195
+ memo + "`#{c.name}`, "
196
+ end)[0..-3]
197
+ else
198
+ event.user.pm(available_commands.reduce("**List of commands:**\n") { |m, e| m + "`#{e.name}`, " }[0..-3])
199
+ event.channel.pm? ? '' : 'Sending list in PM!'
200
+ end
201
+ end
202
+ end
203
+ end
204
+
205
+ # Returns all aliases for the command with the given name
206
+ # @param name [Symbol] the name of the `Command`
207
+ # @return [Array<CommandAlias>]
208
+ end
209
+ end
@@ -19,7 +19,7 @@ module OnyxCord::Commands
19
19
  # creates {CommandAlias} objects in the container ({#commands}) that refer to the newly created command.
20
20
  # Additionally, the default help command will identify these command names as an alias where applicable.
21
21
  # @option attributes [Integer] :permission_level The minimum permission level that can use this command, inclusive.
22
- # See {CommandBot#set_user_permission} and {CommandBot#set_role_permission}.
22
+ # See {Commands::Bot#set_user_permission} and {Commands::Bot#set_role_permission}.
23
23
  # @option attributes [String, false] :permission_message Message to display when a user does not have sufficient
24
24
  # permissions to execute a command. %name% in the message will be replaced with the name of the command. Disable
25
25
  # the message by setting this option to false.
@@ -34,7 +34,7 @@ module OnyxCord::Commands
34
34
  # @option attributes [true, false] :chain_usable Whether this command is able to be used inside of a command chain
35
35
  # or sub-chain. Typically used for administrative commands that shouldn't be done carelessly.
36
36
  # @option attributes [true, false] :help_available Whether this command is visible in the help command. See the
37
- # :help_command attribute of {CommandBot#initialize}.
37
+ # :help_command attribute of {Commands::Bot#initialize}.
38
38
  # @option attributes [String] :description A short description of what this command does. Will be shown in the help
39
39
  # command if the user asks for it.
40
40
  # @option attributes [String] :usage A short description of how this command should be used. Will be displayed in
@@ -93,6 +93,25 @@ module OnyxCord::Commands
93
93
  @commands.merge! handlers
94
94
  end
95
95
 
96
+ # Registers a before or after hook on an existing command.
97
+ # @param command_name [Symbol] The name of the command to hook.
98
+ # @param type [:before, :after] The hook type.
99
+ # @yieldparam event [CommandEvent] The event.
100
+ # @yieldparam args [Array<String>] The command arguments.
101
+ # @yieldparam result [Object] The command result (after hooks only).
102
+ # @return [self]
103
+ def middleware(command_name, type = :before, &hook)
104
+ cmd = @commands&.fetch(command_name, nil)
105
+ cmd = cmd.aliased_command if cmd.is_a?(CommandAlias)
106
+ return self unless cmd.is_a?(Command)
107
+
108
+ case type
109
+ when :before then cmd.before(&hook)
110
+ when :after then cmd.after(&hook)
111
+ end
112
+ self
113
+ end
114
+
96
115
  # Includes another container into this one.
97
116
  # @param container [Module] An EventContainer or CommandContainer that will be included if it can.
98
117
  def include!(container)
@@ -69,9 +69,31 @@ module OnyxCord::Commands
69
69
  aliases: attributes[:aliases] || []
70
70
  }
71
71
 
72
+ @before_hooks = []
73
+ @after_hooks = []
72
74
  @block = block
73
75
  end
74
76
 
77
+ # Registers a before hook. The hook receives the event and arguments.
78
+ # Return +false+ to cancel command execution.
79
+ # @yieldparam event [CommandEvent] The event.
80
+ # @yieldparam args [Array<String>] The command arguments.
81
+ # @return [self]
82
+ def before(&hook)
83
+ @before_hooks << hook
84
+ self
85
+ end
86
+
87
+ # Registers an after hook. The hook receives the event, arguments, and the result.
88
+ # @yieldparam event [CommandEvent] The event.
89
+ # @yieldparam args [Array<String>] The command arguments.
90
+ # @yieldparam result [Object] The return value of the command block.
91
+ # @return [self]
92
+ def after(&hook)
93
+ @after_hooks << hook
94
+ self
95
+ end
96
+
75
97
  # Calls this command and executes the code inside.
76
98
  # @param event [CommandEvent] The event to call the command with.
77
99
  # @param arguments [Array<String>] The attributes for the command.
@@ -105,8 +127,15 @@ module OnyxCord::Commands
105
127
  end
106
128
  end
107
129
 
130
+ cancelled = @before_hooks.any? { |hook| hook.call(event, *arguments).is_a?(FalseClass) }
131
+ return if cancelled
132
+
108
133
  result = @block.call(event, *arguments)
109
134
  event.drain_into(result)
135
+
136
+ @after_hooks.each { |hook| hook.call(event, *arguments, result) }
137
+
138
+ result
110
139
  rescue LocalJumpError => e # occurs when breaking
111
140
  result = e.exit_value
112
141
  event.drain_into(result)
@@ -138,7 +167,7 @@ module OnyxCord::Commands
138
167
  # Command chain, may have multiple commands, nested and commands
139
168
  class CommandChain
140
169
  # @param chain [String] The string the chain should be parsed from.
141
- # @param bot [CommandBot] The bot that executes this command chain.
170
+ # @param bot [Commands::Bot] The bot that executes this command chain.
142
171
  # @param subchain [true, false] Whether this chain is a sub chain of another chain.
143
172
  def initialize(chain, bot, subchain = false)
144
173
  @attributes = bot.attributes