onyxcord 1.1.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 (133) hide show
  1. checksums.yaml +7 -0
  2. data/.devcontainer/Dockerfile +13 -0
  3. data/.devcontainer/devcontainer.json +29 -0
  4. data/.devcontainer/postcreate.sh +4 -0
  5. data/.github/CONTRIBUTING.md +13 -0
  6. data/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  7. data/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
  8. data/.github/pull_request_template.md +37 -0
  9. data/.github/workflows/ci.yml +78 -0
  10. data/.github/workflows/codeql.yml +65 -0
  11. data/.github/workflows/deploy.yml +54 -0
  12. data/.github/workflows/release.yml +51 -0
  13. data/.gitignore +16 -0
  14. data/.markdownlint.json +4 -0
  15. data/.overcommit.yml +7 -0
  16. data/.rspec +2 -0
  17. data/.rubocop.yml +129 -0
  18. data/.yardopts +1 -0
  19. data/CHANGELOG.md +0 -0
  20. data/Gemfile +7 -0
  21. data/LICENSE.txt +21 -0
  22. data/README.md +305 -0
  23. data/Rakefile +17 -0
  24. data/bin/console +15 -0
  25. data/bin/setup +7 -0
  26. data/lib/onyxcord/allowed_mentions.rb +43 -0
  27. data/lib/onyxcord/api/application.rb +316 -0
  28. data/lib/onyxcord/api/channel.rb +700 -0
  29. data/lib/onyxcord/api/interaction.rb +67 -0
  30. data/lib/onyxcord/api/invite.rb +44 -0
  31. data/lib/onyxcord/api/server.rb +775 -0
  32. data/lib/onyxcord/api/user.rb +158 -0
  33. data/lib/onyxcord/api/webhook.rb +163 -0
  34. data/lib/onyxcord/api.rb +335 -0
  35. data/lib/onyxcord/await.rb +51 -0
  36. data/lib/onyxcord/bot.rb +1971 -0
  37. data/lib/onyxcord/cache.rb +326 -0
  38. data/lib/onyxcord/colour_rgb.rb +43 -0
  39. data/lib/onyxcord/commands/command_bot.rb +511 -0
  40. data/lib/onyxcord/commands/container.rb +112 -0
  41. data/lib/onyxcord/commands/events.rb +11 -0
  42. data/lib/onyxcord/commands/parser.rb +327 -0
  43. data/lib/onyxcord/commands/rate_limiter.rb +144 -0
  44. data/lib/onyxcord/configuration.rb +125 -0
  45. data/lib/onyxcord/container.rb +988 -0
  46. data/lib/onyxcord/data/activity.rb +271 -0
  47. data/lib/onyxcord/data/application.rb +341 -0
  48. data/lib/onyxcord/data/attachment.rb +91 -0
  49. data/lib/onyxcord/data/audit_logs.rb +438 -0
  50. data/lib/onyxcord/data/avatar_decoration.rb +26 -0
  51. data/lib/onyxcord/data/call.rb +22 -0
  52. data/lib/onyxcord/data/channel.rb +1355 -0
  53. data/lib/onyxcord/data/channel_tag.rb +69 -0
  54. data/lib/onyxcord/data/collectibles.rb +47 -0
  55. data/lib/onyxcord/data/component.rb +583 -0
  56. data/lib/onyxcord/data/embed.rb +258 -0
  57. data/lib/onyxcord/data/emoji.rb +123 -0
  58. data/lib/onyxcord/data/install_params.rb +24 -0
  59. data/lib/onyxcord/data/integration.rb +144 -0
  60. data/lib/onyxcord/data/interaction.rb +1141 -0
  61. data/lib/onyxcord/data/invite.rb +137 -0
  62. data/lib/onyxcord/data/member.rb +528 -0
  63. data/lib/onyxcord/data/message.rb +612 -0
  64. data/lib/onyxcord/data/message_activity.rb +41 -0
  65. data/lib/onyxcord/data/overwrite.rb +109 -0
  66. data/lib/onyxcord/data/poll.rb +365 -0
  67. data/lib/onyxcord/data/primary_server.rb +60 -0
  68. data/lib/onyxcord/data/profile.rb +79 -0
  69. data/lib/onyxcord/data/reaction.rb +64 -0
  70. data/lib/onyxcord/data/recipient.rb +34 -0
  71. data/lib/onyxcord/data/role.rb +449 -0
  72. data/lib/onyxcord/data/role_connection_data.rb +69 -0
  73. data/lib/onyxcord/data/role_subscription.rb +41 -0
  74. data/lib/onyxcord/data/scheduled_event.rb +513 -0
  75. data/lib/onyxcord/data/server.rb +1614 -0
  76. data/lib/onyxcord/data/server_preview.rb +68 -0
  77. data/lib/onyxcord/data/snapshot.rb +112 -0
  78. data/lib/onyxcord/data/team.rb +98 -0
  79. data/lib/onyxcord/data/timestamp.rb +69 -0
  80. data/lib/onyxcord/data/user.rb +324 -0
  81. data/lib/onyxcord/data/voice_region.rb +46 -0
  82. data/lib/onyxcord/data/voice_state.rb +41 -0
  83. data/lib/onyxcord/data/webhook.rb +238 -0
  84. data/lib/onyxcord/data.rb +57 -0
  85. data/lib/onyxcord/errors.rb +246 -0
  86. data/lib/onyxcord/event_executor.rb +80 -0
  87. data/lib/onyxcord/events/await.rb +48 -0
  88. data/lib/onyxcord/events/bans.rb +60 -0
  89. data/lib/onyxcord/events/channels.rb +225 -0
  90. data/lib/onyxcord/events/generic.rb +129 -0
  91. data/lib/onyxcord/events/guilds.rb +269 -0
  92. data/lib/onyxcord/events/integrations.rb +100 -0
  93. data/lib/onyxcord/events/interactions.rb +624 -0
  94. data/lib/onyxcord/events/invites.rb +127 -0
  95. data/lib/onyxcord/events/lifetime.rb +31 -0
  96. data/lib/onyxcord/events/members.rb +110 -0
  97. data/lib/onyxcord/events/message.rb +399 -0
  98. data/lib/onyxcord/events/polls.rb +118 -0
  99. data/lib/onyxcord/events/presence.rb +131 -0
  100. data/lib/onyxcord/events/raw.rb +74 -0
  101. data/lib/onyxcord/events/reactions.rb +218 -0
  102. data/lib/onyxcord/events/roles.rb +87 -0
  103. data/lib/onyxcord/events/scheduled_events.rb +171 -0
  104. data/lib/onyxcord/events/threads.rb +100 -0
  105. data/lib/onyxcord/events/typing.rb +73 -0
  106. data/lib/onyxcord/events/voice_server_update.rb +48 -0
  107. data/lib/onyxcord/events/voice_state_update.rb +106 -0
  108. data/lib/onyxcord/events/webhooks.rb +65 -0
  109. data/lib/onyxcord/gateway.rb +890 -0
  110. data/lib/onyxcord/id_object.rb +39 -0
  111. data/lib/onyxcord/light/data.rb +62 -0
  112. data/lib/onyxcord/light/integrations.rb +73 -0
  113. data/lib/onyxcord/light/light_bot.rb +58 -0
  114. data/lib/onyxcord/light.rb +8 -0
  115. data/lib/onyxcord/logger.rb +120 -0
  116. data/lib/onyxcord/message_components.rb +70 -0
  117. data/lib/onyxcord/paginator.rb +60 -0
  118. data/lib/onyxcord/permissions.rb +255 -0
  119. data/lib/onyxcord/rate_limiter/gateway.rb +42 -0
  120. data/lib/onyxcord/rate_limiter/rest.rb +89 -0
  121. data/lib/onyxcord/version.rb +7 -0
  122. data/lib/onyxcord/voice/encoder.rb +115 -0
  123. data/lib/onyxcord/voice/network.rb +380 -0
  124. data/lib/onyxcord/voice/opcodes.rb +29 -0
  125. data/lib/onyxcord/voice/sodium.rb +157 -0
  126. data/lib/onyxcord/voice/timer.rb +19 -0
  127. data/lib/onyxcord/voice/voice_bot.rb +386 -0
  128. data/lib/onyxcord/webhooks.rb +14 -0
  129. data/lib/onyxcord/websocket.rb +62 -0
  130. data/lib/onyxcord.rb +180 -0
  131. data/onyxcord-webhooks.gemspec +30 -0
  132. data/onyxcord.gemspec +50 -0
  133. metadata +421 -0
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnyxCord::Events
4
+ # Raised when an invite is created.
5
+ class InviteCreateEvent < Event
6
+ # @return [Invite] The invite that was created.
7
+ attr_reader :invite
8
+
9
+ # @return [Server, nil] The server the invite was created for.
10
+ attr_reader :server
11
+
12
+ # @return [Channel] The channel the invite was created for.
13
+ attr_reader :channel
14
+
15
+ # @!attribute [r] code
16
+ # @return [String] The code for the created invite.
17
+ # @see Invite#code
18
+ # @!attribute [r] created_at
19
+ # @return [Time] The time the invite was created at.
20
+ # @see Invite#created_at
21
+ # @!attribute [r] max_age
22
+ # @return [Integer] The maximum age of the created invite.
23
+ # @see Invite#max_age
24
+ # @!attribute [r] max_uses
25
+ # @return [Integer] The maximum number of uses before the invite expires.
26
+ # @see Invite#max_uses
27
+ # @!attribute [r] temporary
28
+ # @return [true, false] Whether or not this invite grants temporary membership.
29
+ # @see Invite#temporary
30
+ # @!attribute [r] inviter
31
+ # @return [User] The user that created the invite.
32
+ # @see Invite#inviter
33
+ delegate :code, :created_at, :max_age, :max_uses, :temporary, :inviter, to: :invite
34
+
35
+ alias temporary? temporary
36
+
37
+ # @!visibility private
38
+ def initialize(data, invite, bot)
39
+ @bot = bot
40
+ @invite = invite
41
+ @channel = bot.channel(data['channel_id'])
42
+ @server = bot.server(data['guild_id']) if data['guild_id']
43
+ end
44
+ end
45
+
46
+ # Raised when an invite is deleted.
47
+ class InviteDeleteEvent < Event
48
+ # @return [Channel] The channel the deleted invite was for.
49
+ attr_reader :channel
50
+
51
+ # @return [Server, nil] The server the deleted invite was for.
52
+ attr_reader :server
53
+
54
+ # @return [String] The code of the deleted invite.
55
+ attr_reader :code
56
+
57
+ # @!visibility private
58
+ def initialize(data, bot)
59
+ @bot = bot
60
+ @channel = bot.channel(data['channel_id'])
61
+ @server = bot.server(data['guild_id']) if data['guild_id']
62
+ @code = data['code']
63
+ end
64
+ end
65
+
66
+ # Event handler for InviteCreateEvent.
67
+ class InviteCreateEventHandler < EventHandler
68
+ def matches?(event)
69
+ return false unless event.is_a? InviteCreateEvent
70
+
71
+ [
72
+ matches_all(@attributes[:server], event.server) do |a, e|
73
+ a == case a
74
+ when String
75
+ e.name
76
+ when Integer
77
+ e.id
78
+ else
79
+ e
80
+ end
81
+ end,
82
+ matches_all(@attributes[:channel], event.channel) do |a, e|
83
+ a == case a
84
+ when String
85
+ e.name
86
+ when Integer
87
+ e.id
88
+ else
89
+ e
90
+ end
91
+ end,
92
+ matches_all(@attributes[:temporary], event.temporary?, &:==),
93
+ matches_all(@attributes[:inviter], event.inviter, &:==)
94
+ ].reduce(true, &:&)
95
+ end
96
+ end
97
+
98
+ # Event handler for InviteDeleteEvent
99
+ class InviteDeleteEventHandler < EventHandler
100
+ def matches?(event)
101
+ return false unless event.is_a? InviteDeleteEvent
102
+
103
+ [
104
+ matches_all(@attributes[:server], event.server) do |a, e|
105
+ a == case a
106
+ when String
107
+ e.name
108
+ when Integer
109
+ e.id
110
+ else
111
+ e
112
+ end
113
+ end,
114
+ matches_all(@attributes[:channel], event.channel) do |a, e|
115
+ a == case a
116
+ when String
117
+ e.name
118
+ when Integer
119
+ e.id
120
+ else
121
+ e
122
+ end
123
+ end
124
+ ].reduce(true, &:&)
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'onyxcord/events/generic'
4
+
5
+ module OnyxCord::Events
6
+ # Common superclass for all lifetime events
7
+ class LifetimeEvent < Event
8
+ # @!visibility private
9
+ def initialize(bot)
10
+ @bot = bot
11
+ end
12
+ end
13
+
14
+ # @see OnyxCord::EventContainer#ready
15
+ class ReadyEvent < LifetimeEvent; end
16
+
17
+ # Event handler for {ReadyEvent}
18
+ class ReadyEventHandler < TrueEventHandler; end
19
+
20
+ # @see OnyxCord::EventContainer#disconnected
21
+ class DisconnectEvent < LifetimeEvent; end
22
+
23
+ # Event handler for {DisconnectEvent}
24
+ class DisconnectEventHandler < TrueEventHandler; end
25
+
26
+ # @see OnyxCord::EventContainer#heartbeat
27
+ class HeartbeatEvent < LifetimeEvent; end
28
+
29
+ # Event handler for {HeartbeatEvent}
30
+ class HeartbeatEventHandler < TrueEventHandler; end
31
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'onyxcord/events/generic'
4
+ require 'onyxcord/data'
5
+
6
+ module OnyxCord::Events
7
+ # Generic subclass for server member events (add/update/delete)
8
+ class ServerMemberEvent < Event
9
+ # @return [Member] the member in question.
10
+ attr_reader :user
11
+ alias_method :member, :user
12
+
13
+ # @return [Array<Role>] the member's roles.
14
+ attr_reader :roles
15
+
16
+ # @return [Server] the server on which the event happened.
17
+ attr_reader :server
18
+
19
+ # @!visibility private
20
+ def initialize(data, bot)
21
+ @bot = bot
22
+
23
+ @server = bot.server(data['guild_id'].to_i)
24
+ return unless @server
25
+
26
+ init_user(data, bot)
27
+ init_roles(data, bot)
28
+ end
29
+
30
+ private
31
+
32
+ # @!visibility private
33
+ def init_user(data, _)
34
+ user_id = data['user']['id'].to_i
35
+ @user = @server.member(user_id)
36
+ end
37
+
38
+ # @!visibility private
39
+ def init_roles(data, _)
40
+ @roles = [@server.role(@server.id)]
41
+ return unless data['roles']
42
+
43
+ data['roles'].each do |element|
44
+ role_id = element.to_i
45
+ @roles << @server.roles.find { |r| r.id == role_id }
46
+ end
47
+ end
48
+ end
49
+
50
+ # Generic event handler for member events
51
+ class ServerMemberEventHandler < EventHandler
52
+ def matches?(event)
53
+ # Check for the proper event type
54
+ return false unless event.is_a? ServerMemberEvent
55
+
56
+ [
57
+ matches_all(@attributes[:username], event.user.name) do |a, e|
58
+ a == if a.is_a? String
59
+ e.to_s
60
+ else
61
+ e
62
+ end
63
+ end
64
+ ].reduce(true, &:&)
65
+ end
66
+ end
67
+
68
+ # Member joins
69
+ # @see OnyxCord::EventContainer#member_join
70
+ class ServerMemberAddEvent < ServerMemberEvent; end
71
+
72
+ # Event handler for {ServerMemberAddEvent}
73
+ class ServerMemberAddEventHandler < ServerMemberEventHandler; end
74
+
75
+ # Member is updated (roles added or deleted)
76
+ # @see OnyxCord::EventContainer#member_update
77
+ class ServerMemberUpdateEvent < ServerMemberEvent
78
+ # @!visibility private
79
+ # @note Override init_user so we don't make requests all the time on large servers
80
+ def init_user(data, _)
81
+ @user_id = data['user']['id']
82
+ end
83
+
84
+ # @return [Member] the member in question.
85
+ def user
86
+ @server&.member(@user_id)
87
+ end
88
+
89
+ alias_method :member, :user
90
+ end
91
+
92
+ # Event handler for {ServerMemberUpdateEvent}
93
+ class ServerMemberUpdateEventHandler < ServerMemberEventHandler; end
94
+
95
+ # Member leaves
96
+ # @see OnyxCord::EventContainer#member_leave
97
+ class ServerMemberDeleteEvent < ServerMemberEvent
98
+ # @!visibility private
99
+ # @note Override init_user to account for the deleted user on the server
100
+ def init_user(data, bot)
101
+ @user = OnyxCord::User.new(data['user'], bot)
102
+ end
103
+
104
+ # @return [User] the user in question.
105
+ attr_reader :user
106
+ end
107
+
108
+ # Event handler for {ServerMemberDeleteEvent}
109
+ class ServerMemberDeleteEventHandler < ServerMemberEventHandler; end
110
+ end
@@ -0,0 +1,399 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'onyxcord/events/generic'
4
+ require 'onyxcord/data'
5
+
6
+ module OnyxCord::Events
7
+ # Module to make sending messages easier with the presence of a text channel in an event
8
+ module Respondable
9
+ # @return [Channel] the channel in which this event occurred
10
+ attr_reader :channel
11
+
12
+ # Sends a message to the channel this message was sent in, right now. It is usually preferable to use {#<<} instead
13
+ # because it avoids rate limiting problems
14
+ # @param content [String] The message to send to the channel
15
+ # @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
16
+ # @param embed [Hash, OnyxCord::Webhooks::Embed, nil] The rich embed to append to this message.
17
+ # @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
18
+ # @param allowed_mentions [Hash, OnyxCord::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
19
+ # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
20
+ # @param components [View, Array<Hash>, nil] A collection of components to attach to the message.
21
+ # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
22
+ # @return [OnyxCord::Message] the message that was sent
23
+ def send_message(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0)
24
+ channel.send_message(content, tts, embed, attachments, allowed_mentions, message_reference, components, flags)
25
+ end
26
+
27
+ # The same as {#send_message}, but yields a {Webhooks::Embed} for easy building of embedded content inside a block.
28
+ # @see Channel#send_embed
29
+ # @param message [String] The message that should be sent along with the embed. If this is the empty string, only the embed will be shown.
30
+ # @param embed [OnyxCord::Webhooks::Embed, nil] The embed to start the building process with, or nil if one should be created anew.
31
+ # @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
32
+ # @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
33
+ # @param allowed_mentions [Hash, OnyxCord::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
34
+ # @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
35
+ # @param components [View, Array<Hash>, nil] A collection of components to attach to the message.
36
+ # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
37
+ # @yield [embed] Yields the embed to allow for easy building inside a block.
38
+ # @yieldparam embed [OnyxCord::Webhooks::Embed] The embed from the parameters, or a new one.
39
+ # @return [Message] The resulting message.
40
+ def send_embed(message = '', embed = nil, attachments = nil, tts = false, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0, &block)
41
+ channel.send_embed(message, embed, attachments, tts, allowed_mentions, message_reference, components, flags, &block)
42
+ end
43
+
44
+ # Sends a temporary message to the channel this message was sent in, right now.
45
+ # @param content [String] The content to send. Should not be longer than 2000 characters or it will result in an error.
46
+ # @param timeout [Float] The amount of time in seconds after which the message sent will be deleted.
47
+ # @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
48
+ # @param embed [Hash, OnyxCord::Webhooks::Embed, nil] The rich embed to append to this message.
49
+ # @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
50
+ # @param allowed_mentions [Hash, OnyxCord::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
51
+ # @param components [View, Array<Hash>, nil] A collection of components to attach to the message.
52
+ # @param flags [Integer] Flags for this message. Currently only SUPPRESS_EMBEDS (1 << 2), SUPPRESS_NOTIFICATIONS (1 << 12), and IS_COMPONENTS_V2 (1 << 15) can be set.
53
+ def send_temporary_message(content, timeout, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, components = nil, flags = 0)
54
+ channel.send_temporary_message(content, timeout, tts, embed, attachments, allowed_mentions, components, flags)
55
+ end
56
+
57
+ # Sends a message to the channel this message was sent in, right now.
58
+ # @see Channel#send_message!
59
+ def send_message!(...)
60
+ channel.send_message!(...)
61
+ end
62
+
63
+ # Adds a string to be sent after the event has finished execution. Avoids problems with rate limiting because only
64
+ # one message is ever sent. If it is used multiple times, the strings will bunch up into one message (separated by
65
+ # newlines)
66
+ # @param message [String] The message to send to the channel
67
+ def <<(message)
68
+ addition = "#{message}\n"
69
+ @saved_message = @saved_message ? @saved_message + addition : addition
70
+ nil
71
+ end
72
+
73
+ # Drains the currently saved message, which clears it out, resulting in everything being saved before being
74
+ # thrown away and nothing being sent to the channel (unless there is something saved after this).
75
+ # @see #<<
76
+ def drain
77
+ @saved_message = ''
78
+ nil
79
+ end
80
+
81
+ # Drains the currently saved message into a result string. This prepends it before that string, clears the saved
82
+ # message and returns the concatenation.
83
+ # @param result [String] The result string to drain into.
84
+ # @return [String] a string formed by concatenating the saved message and the argument.
85
+ def drain_into(result)
86
+ return if result.is_a?(OnyxCord::Message)
87
+
88
+ result = (@saved_message.nil? ? '' : @saved_message.to_s) + (result.nil? ? '' : result.to_s)
89
+ drain
90
+ result
91
+ end
92
+
93
+ alias_method :send, :send_message
94
+ alias_method :respond, :send_message
95
+ alias_method :send_temp, :send_temporary_message
96
+
97
+ alias_method :send!, :send_message!
98
+ alias_method :respond!, :send_message!
99
+ end
100
+
101
+ # Event raised when a text message is sent to a channel
102
+ class MessageEvent < Event
103
+ include Respondable
104
+
105
+ # @return [Message] the message which triggered this event.
106
+ attr_reader :message
107
+
108
+ # @return [String] the message that has been saved by calls to {#<<} and will be sent to Discord upon completion.
109
+ attr_reader :saved_message
110
+
111
+ # @return [File] the file that has been saved by a call to {#attach_file} and will be sent to Discord upon completion.
112
+ attr_reader :file
113
+
114
+ # @return [String] the filename set in {#attach_file} that will override the original filename when sent.
115
+ attr_reader :filename
116
+
117
+ # @return [true, false] Whether or not this file should appear as a spoiler. Set by {#attach_file}
118
+ attr_reader :file_spoiler
119
+
120
+ # @!attribute [r] author
121
+ # @return [Member, User] who sent this message.
122
+ # @see Message#author
123
+ # @!attribute [r] channel
124
+ # @return [Channel] the channel in which this message was sent.
125
+ # @see Message#channel
126
+ # @!attribute [r] content
127
+ # @return [String] the message's content.
128
+ # @see Message#content
129
+ # @!attribute [r] timestamp
130
+ # @return [Time] the time at which the message was sent.
131
+ # @see Message#timestamp
132
+ delegate :author, :channel, :content, :timestamp, to: :message
133
+
134
+ # @!attribute [r] server
135
+ # @return [Server, nil] the server where this message was sent, or nil if it was sent in PM.
136
+ # @see Channel#server
137
+ delegate :server, to: :channel
138
+
139
+ # @!visibility private
140
+ def initialize(message, bot)
141
+ @bot = bot
142
+ @message = message
143
+ @channel = message.channel
144
+ @saved_message = ''
145
+ @file = nil
146
+ @filename = nil
147
+ @file_spoiler = nil
148
+ end
149
+
150
+ # Sends file with a caption to the channel this message was sent in, right now.
151
+ # It is usually preferable to use {#<<} and {#attach_file} instead
152
+ # because it avoids rate limiting problems
153
+ # @param file [File] The file to send to the channel
154
+ # @param caption [String] The caption attached to the file
155
+ # @param filename [String] Overrides the filename of the uploaded file
156
+ # @param spoiler [true, false] Whether or not this file should appear as a spoiler.
157
+ # @return [OnyxCord::Message] the message that was sent
158
+ # @example Send a file from disk
159
+ # event.send_file(File.open('rubytaco.png', 'r'))
160
+ def send_file(file, caption: nil, filename: nil, spoiler: nil)
161
+ @message.channel.send_file(file, caption: caption, filename: filename, spoiler: spoiler)
162
+ end
163
+
164
+ # Attaches a file to the message event and converts the message into
165
+ # a caption.
166
+ # @param file [File] The file to be attached
167
+ # @param filename [String] Overrides the filename of the uploaded file
168
+ # @param spoiler [true, false] Whether or not this file should appear as a spoiler.
169
+ def attach_file(file, filename: nil, spoiler: nil)
170
+ raise ArgumentError, 'Argument is not a file!' unless file.is_a?(File)
171
+
172
+ @file = file
173
+ @filename = filename
174
+ @file_spoiler = spoiler
175
+ nil
176
+ end
177
+
178
+ # Detaches a file from the message event.
179
+ def detach_file
180
+ @file = nil
181
+ @filename = nil
182
+ @file_spoiler = nil
183
+ end
184
+
185
+ # @return [true, false] whether or not this message was sent by the bot itself
186
+ def from_bot?
187
+ @message.user.id == @bot.profile.id
188
+ end
189
+
190
+ # Utility method to get the voice bot for the current server
191
+ # @return [VoiceBot, nil] the voice bot connected to this message's server, or nil if there is none connected
192
+ def voice
193
+ @bot.voice(@message.channel.server.id)
194
+ end
195
+
196
+ alias_method :user, :author
197
+ alias_method :text, :content
198
+ end
199
+
200
+ # Event handler for MessageEvent
201
+ class MessageEventHandler < EventHandler
202
+ def matches?(event)
203
+ # Check for the proper event type
204
+ return false unless event.is_a? MessageEvent
205
+
206
+ [
207
+ matches_all(@attributes[:starting_with] || @attributes[:start_with], event.content) do |a, e|
208
+ case a
209
+ when String
210
+ e.start_with? a
211
+ when Regexp
212
+ (e =~ a)&.zero?
213
+ end
214
+ end,
215
+ matches_all(@attributes[:ending_with] || @attributes[:end_with], event.content) do |a, e|
216
+ case a
217
+ when String
218
+ e.end_with? a
219
+ when Regexp
220
+ !(e =~ Regexp.new("#{a}$")).nil?
221
+ end
222
+ end,
223
+ matches_all(@attributes[:containing] || @attributes[:contains], event.content) do |a, e|
224
+ case a
225
+ when String
226
+ e.include? a
227
+ when Regexp
228
+ (e =~ a)
229
+ end
230
+ end,
231
+ matches_all(@attributes[:in], event.channel) do |a, e|
232
+ case a
233
+ when String
234
+ # Make sure to remove the "#" from channel names in case it was specified
235
+ a.delete('#') == e.name
236
+ when Integer
237
+ a == e.id
238
+ else
239
+ a == e
240
+ end
241
+ end,
242
+ matches_all(@attributes[:from], event.message) do |a, e|
243
+ # Resolve the author in the block in order to prevent resolving the author even when the attribute is `nil`
244
+ e = e.author
245
+ case a
246
+ when String
247
+ a == e.name
248
+ when Integer
249
+ a == e.id
250
+ when :bot
251
+ e.current_bot?
252
+ else
253
+ a == e
254
+ end
255
+ end,
256
+ matches_all(@attributes[:with_text] || @attributes[:content] || @attributes[:exact_text], event.content) do |a, e|
257
+ case a
258
+ when String
259
+ e == a
260
+ when Regexp
261
+ match = a.match(e)
262
+ match ? (e == match[0]) : false
263
+ end
264
+ end,
265
+ matches_all(@attributes[:type] || @attributes[:message_type], event.message.type) do |a, e|
266
+ case a
267
+ when String, Symbol
268
+ OnyxCord::Message::TYPES[a.to_sym] == e
269
+ when Integer
270
+ a == e
271
+ end
272
+ end,
273
+ matches_all(@attributes[:after], event.timestamp) { |a, e| a > e },
274
+ matches_all(@attributes[:before], event.timestamp) { |a, e| a < e },
275
+ matches_all(@attributes[:private], event.channel.private?) { |a, e| !e == !a },
276
+ matches_all(@attributes[:server], event.server) { |a, e| a&.resolve_id == e&.resolve_id }
277
+ ].reduce(true, &:&)
278
+ end
279
+
280
+ # @see EventHandler#after_call
281
+ def after_call(event)
282
+ if event.file.nil?
283
+ event.send_message(event.saved_message) unless event.saved_message.empty?
284
+ else
285
+ event.send_file(event.file, caption: event.saved_message, filename: event.filename, spoiler: event.file_spoiler)
286
+ end
287
+ end
288
+ end
289
+
290
+ # Event raised when the current bot is mentioned in a message.
291
+ class MentionEvent < MessageEvent
292
+ # @return [true, false] whether this mention event was raised
293
+ # due to a mention of the bot's auto-generated server role.
294
+ attr_reader :role_mention
295
+ alias_method :role_mention?, :role_mention
296
+
297
+ # @!visibility private
298
+ def initialize(message, bot, role_mention)
299
+ super(message, bot)
300
+
301
+ @role_mention = role_mention
302
+ end
303
+ end
304
+
305
+ # Event handler for {MentionEvent}
306
+ class MentionEventHandler < MessageEventHandler
307
+ # @!visibility private
308
+ def matches?(event)
309
+ return false unless super
310
+ return false unless event.is_a?(MentionEvent)
311
+
312
+ [
313
+ matches_all(@attributes[:role_mention], event.role_mention) do |a, e|
314
+ case a
315
+ when TrueClass
316
+ e == true
317
+ when FalseClass
318
+ e == false
319
+ end
320
+ end
321
+ ].reduce(true, &:&)
322
+ end
323
+ end
324
+
325
+ # @see OnyxCord::EventContainer#pm
326
+ class PrivateMessageEvent < MessageEvent; end
327
+
328
+ # Event handler for {PrivateMessageEvent}
329
+ class PrivateMessageEventHandler < MessageEventHandler; end
330
+
331
+ # A subset of MessageEvent that only contains a message ID and a channel
332
+ class MessageIDEvent < Event
333
+ include Respondable
334
+
335
+ # @return [Integer] the ID associated with this event
336
+ attr_reader :id
337
+
338
+ # @return [Server, nil] the server associated with this event
339
+ attr_reader :server
340
+
341
+ # @!visibility private
342
+ def initialize(data, bot)
343
+ @id = data['id'].to_i
344
+ @channel = bot.channel(data['channel_id'].to_i)
345
+ @server = @channel.server
346
+ @saved_message = ''
347
+ @bot = bot
348
+ end
349
+ end
350
+
351
+ # Event handler for {MessageIDEvent}
352
+ class MessageIDEventHandler < EventHandler
353
+ def matches?(event)
354
+ # Check for the proper event type
355
+ return false unless event.is_a? MessageIDEvent
356
+
357
+ [
358
+ matches_all(@attributes[:id], event.id) do |a, e|
359
+ a.resolve_id == e.resolve_id
360
+ end,
361
+ matches_all(@attributes[:in], event.channel) do |a, e|
362
+ case a
363
+ when String
364
+ # Make sure to remove the "#" from channel names in case it was specified
365
+ a.delete('#') == e.name
366
+ when Integer
367
+ a == e.id
368
+ else
369
+ a == e
370
+ end
371
+ end,
372
+ matches_all(@attributes[:server], event.server) do |a, e|
373
+ a&.resolve_id == e&.resolve_id
374
+ end
375
+ ].reduce(true, &:&)
376
+ end
377
+ end
378
+
379
+ # Raised when a message is edited
380
+ # @see OnyxCord::EventContainer#message_edit
381
+ class MessageEditEvent < MessageEvent; end
382
+
383
+ # Event handler for {MessageEditEvent}
384
+ class MessageEditEventHandler < MessageEventHandler; end
385
+
386
+ # Raised when a message is deleted
387
+ # @see OnyxCord::EventContainer#message_delete
388
+ class MessageDeleteEvent < MessageIDEvent; end
389
+
390
+ # Event handler for {MessageDeleteEvent}
391
+ class MessageDeleteEventHandler < MessageIDEventHandler; end
392
+
393
+ # Raised whenever a MESSAGE_UPDATE is received
394
+ # @see OnyxCord::EventContainer#message_update
395
+ class MessageUpdateEvent < MessageEvent; end
396
+
397
+ # Event handler for {MessageUpdateEvent}
398
+ class MessageUpdateEventHandler < MessageEventHandler; end
399
+ end