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.
- checksums.yaml +7 -0
- data/.devcontainer/Dockerfile +13 -0
- data/.devcontainer/devcontainer.json +29 -0
- data/.devcontainer/postcreate.sh +4 -0
- data/.github/CONTRIBUTING.md +13 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
- data/.github/pull_request_template.md +37 -0
- data/.github/workflows/ci.yml +78 -0
- data/.github/workflows/codeql.yml +65 -0
- data/.github/workflows/deploy.yml +54 -0
- data/.github/workflows/release.yml +51 -0
- data/.gitignore +16 -0
- data/.markdownlint.json +4 -0
- data/.overcommit.yml +7 -0
- data/.rspec +2 -0
- data/.rubocop.yml +129 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +0 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +305 -0
- data/Rakefile +17 -0
- data/bin/console +15 -0
- data/bin/setup +7 -0
- data/lib/onyxcord/allowed_mentions.rb +43 -0
- data/lib/onyxcord/api/application.rb +316 -0
- data/lib/onyxcord/api/channel.rb +700 -0
- data/lib/onyxcord/api/interaction.rb +67 -0
- data/lib/onyxcord/api/invite.rb +44 -0
- data/lib/onyxcord/api/server.rb +775 -0
- data/lib/onyxcord/api/user.rb +158 -0
- data/lib/onyxcord/api/webhook.rb +163 -0
- data/lib/onyxcord/api.rb +335 -0
- data/lib/onyxcord/await.rb +51 -0
- data/lib/onyxcord/bot.rb +1971 -0
- data/lib/onyxcord/cache.rb +326 -0
- data/lib/onyxcord/colour_rgb.rb +43 -0
- data/lib/onyxcord/commands/command_bot.rb +511 -0
- data/lib/onyxcord/commands/container.rb +112 -0
- data/lib/onyxcord/commands/events.rb +11 -0
- data/lib/onyxcord/commands/parser.rb +327 -0
- data/lib/onyxcord/commands/rate_limiter.rb +144 -0
- data/lib/onyxcord/configuration.rb +125 -0
- data/lib/onyxcord/container.rb +988 -0
- data/lib/onyxcord/data/activity.rb +271 -0
- data/lib/onyxcord/data/application.rb +341 -0
- data/lib/onyxcord/data/attachment.rb +91 -0
- data/lib/onyxcord/data/audit_logs.rb +438 -0
- data/lib/onyxcord/data/avatar_decoration.rb +26 -0
- data/lib/onyxcord/data/call.rb +22 -0
- data/lib/onyxcord/data/channel.rb +1355 -0
- data/lib/onyxcord/data/channel_tag.rb +69 -0
- data/lib/onyxcord/data/collectibles.rb +47 -0
- data/lib/onyxcord/data/component.rb +583 -0
- data/lib/onyxcord/data/embed.rb +258 -0
- data/lib/onyxcord/data/emoji.rb +123 -0
- data/lib/onyxcord/data/install_params.rb +24 -0
- data/lib/onyxcord/data/integration.rb +144 -0
- data/lib/onyxcord/data/interaction.rb +1141 -0
- data/lib/onyxcord/data/invite.rb +137 -0
- data/lib/onyxcord/data/member.rb +528 -0
- data/lib/onyxcord/data/message.rb +612 -0
- data/lib/onyxcord/data/message_activity.rb +41 -0
- data/lib/onyxcord/data/overwrite.rb +109 -0
- data/lib/onyxcord/data/poll.rb +365 -0
- data/lib/onyxcord/data/primary_server.rb +60 -0
- data/lib/onyxcord/data/profile.rb +79 -0
- data/lib/onyxcord/data/reaction.rb +64 -0
- data/lib/onyxcord/data/recipient.rb +34 -0
- data/lib/onyxcord/data/role.rb +449 -0
- data/lib/onyxcord/data/role_connection_data.rb +69 -0
- data/lib/onyxcord/data/role_subscription.rb +41 -0
- data/lib/onyxcord/data/scheduled_event.rb +513 -0
- data/lib/onyxcord/data/server.rb +1614 -0
- data/lib/onyxcord/data/server_preview.rb +68 -0
- data/lib/onyxcord/data/snapshot.rb +112 -0
- data/lib/onyxcord/data/team.rb +98 -0
- data/lib/onyxcord/data/timestamp.rb +69 -0
- data/lib/onyxcord/data/user.rb +324 -0
- data/lib/onyxcord/data/voice_region.rb +46 -0
- data/lib/onyxcord/data/voice_state.rb +41 -0
- data/lib/onyxcord/data/webhook.rb +238 -0
- data/lib/onyxcord/data.rb +57 -0
- data/lib/onyxcord/errors.rb +246 -0
- data/lib/onyxcord/event_executor.rb +80 -0
- data/lib/onyxcord/events/await.rb +48 -0
- data/lib/onyxcord/events/bans.rb +60 -0
- data/lib/onyxcord/events/channels.rb +225 -0
- data/lib/onyxcord/events/generic.rb +129 -0
- data/lib/onyxcord/events/guilds.rb +269 -0
- data/lib/onyxcord/events/integrations.rb +100 -0
- data/lib/onyxcord/events/interactions.rb +624 -0
- data/lib/onyxcord/events/invites.rb +127 -0
- data/lib/onyxcord/events/lifetime.rb +31 -0
- data/lib/onyxcord/events/members.rb +110 -0
- data/lib/onyxcord/events/message.rb +399 -0
- data/lib/onyxcord/events/polls.rb +118 -0
- data/lib/onyxcord/events/presence.rb +131 -0
- data/lib/onyxcord/events/raw.rb +74 -0
- data/lib/onyxcord/events/reactions.rb +218 -0
- data/lib/onyxcord/events/roles.rb +87 -0
- data/lib/onyxcord/events/scheduled_events.rb +171 -0
- data/lib/onyxcord/events/threads.rb +100 -0
- data/lib/onyxcord/events/typing.rb +73 -0
- data/lib/onyxcord/events/voice_server_update.rb +48 -0
- data/lib/onyxcord/events/voice_state_update.rb +106 -0
- data/lib/onyxcord/events/webhooks.rb +65 -0
- data/lib/onyxcord/gateway.rb +890 -0
- data/lib/onyxcord/id_object.rb +39 -0
- data/lib/onyxcord/light/data.rb +62 -0
- data/lib/onyxcord/light/integrations.rb +73 -0
- data/lib/onyxcord/light/light_bot.rb +58 -0
- data/lib/onyxcord/light.rb +8 -0
- data/lib/onyxcord/logger.rb +120 -0
- data/lib/onyxcord/message_components.rb +70 -0
- data/lib/onyxcord/paginator.rb +60 -0
- data/lib/onyxcord/permissions.rb +255 -0
- data/lib/onyxcord/rate_limiter/gateway.rb +42 -0
- data/lib/onyxcord/rate_limiter/rest.rb +89 -0
- data/lib/onyxcord/version.rb +7 -0
- data/lib/onyxcord/voice/encoder.rb +115 -0
- data/lib/onyxcord/voice/network.rb +380 -0
- data/lib/onyxcord/voice/opcodes.rb +29 -0
- data/lib/onyxcord/voice/sodium.rb +157 -0
- data/lib/onyxcord/voice/timer.rb +19 -0
- data/lib/onyxcord/voice/voice_bot.rb +386 -0
- data/lib/onyxcord/webhooks.rb +14 -0
- data/lib/onyxcord/websocket.rb +62 -0
- data/lib/onyxcord.rb +180 -0
- data/onyxcord-webhooks.gemspec +30 -0
- data/onyxcord.gemspec +50 -0
- metadata +421 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OnyxCord
|
|
4
|
+
# Publicly accessible information about a discoverable server.
|
|
5
|
+
class ServerPreview
|
|
6
|
+
include IDObject
|
|
7
|
+
include ServerAttributes
|
|
8
|
+
|
|
9
|
+
# @return [String, nil] the ID of the server's invite splash screen.
|
|
10
|
+
# @see #splash_url
|
|
11
|
+
attr_reader :splash_id
|
|
12
|
+
|
|
13
|
+
# @return [String, nil] the ID of the server's discovery splash screen.
|
|
14
|
+
# @see #discovery_splash_url
|
|
15
|
+
attr_reader :discovery_splash_id
|
|
16
|
+
|
|
17
|
+
# @return [Hash<Integer => Emoji>] a hash of all the emojis usable on this server.
|
|
18
|
+
attr_reader :emojis
|
|
19
|
+
|
|
20
|
+
# @return [Array<Symbol>] the features of this server, e.g. `:banner` or `:verified`.
|
|
21
|
+
attr_reader :features
|
|
22
|
+
|
|
23
|
+
# @return [Integer] the approximate number of members on this server, offline or not.
|
|
24
|
+
attr_reader :member_count
|
|
25
|
+
|
|
26
|
+
# @return [Integer] the approximate number of members that aren't offline on this server.
|
|
27
|
+
attr_reader :presence_count
|
|
28
|
+
|
|
29
|
+
# @return [String, nil] the description of this server that's shown in the discovery tab.
|
|
30
|
+
attr_reader :description
|
|
31
|
+
|
|
32
|
+
# @!visibility private
|
|
33
|
+
def initialize(data, bot)
|
|
34
|
+
@bot = bot
|
|
35
|
+
@id = data['id'].to_i
|
|
36
|
+
@name = data['name']
|
|
37
|
+
@icon_id = data['icon']
|
|
38
|
+
@splash_id = data['splash']
|
|
39
|
+
@description = data['description']
|
|
40
|
+
@discovery_splash_id = data['discovery_splash']
|
|
41
|
+
@member_count = data['approximate_member_count']
|
|
42
|
+
@presence_count = data['approximate_presence_count']
|
|
43
|
+
@features = data['features'].map { |feature| feature.downcase.to_sym }
|
|
44
|
+
@emojis = data['emojis'].to_h { |emoji| [emoji['id'].to_i, Emoji.new(emoji, bot)] }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Get the server associated with this server preview.
|
|
48
|
+
# @return [Server] the server associated with this server preview.
|
|
49
|
+
# @raise [OnyxCord::Errors::NoPermission] this can happen when the bot is not in the associated server.
|
|
50
|
+
def server
|
|
51
|
+
@bot.server(@id)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Utility method to get a server preview's splash URL.
|
|
55
|
+
# @param format [String] the URL will default to `webp`. You can otherwise specify one of `jpg` or `png` to override this.
|
|
56
|
+
# @return [String, nil] the URL to the server's splash image, or `nil` if the server doesn't have a splash image.
|
|
57
|
+
def splash_url(format = 'webp')
|
|
58
|
+
API.splash_url(@id, @splash_id, format) if @splash_id
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Utility method to get a server preview's discovery splash URL.
|
|
62
|
+
# @param format [String] the URL will default to `webp`. You can otherwise specify one of `jpg` or `png` to override this.
|
|
63
|
+
# @return [String, nil] the URL to the server's discovery splash image, or `nil` if the server doesn't have a discovery splash image.
|
|
64
|
+
def discovery_splash_url(format = 'webp')
|
|
65
|
+
API.discovery_splash_url(@id, @discovery_splash_id, format) if @discovery_splash_id
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OnyxCord
|
|
4
|
+
# A partial and immutable copy of a message that has been forwarded.
|
|
5
|
+
class Snapshot
|
|
6
|
+
# @return [Integer] the message type of the message snapshot.
|
|
7
|
+
attr_reader :type
|
|
8
|
+
|
|
9
|
+
# @return [String] the text content of the message snapshot.
|
|
10
|
+
attr_reader :content
|
|
11
|
+
|
|
12
|
+
# @return [Array<Embed>] the embeds attached to the message snapshot.
|
|
13
|
+
attr_reader :embeds
|
|
14
|
+
|
|
15
|
+
# @return [Array<Attachment>] the files attached to the message snapshot.
|
|
16
|
+
attr_reader :attachments
|
|
17
|
+
|
|
18
|
+
# @return [Time] the time at which the message snapshot was created.
|
|
19
|
+
attr_reader :created_at
|
|
20
|
+
|
|
21
|
+
# @return [Time, nil] the time at which the message snapshot was edited.
|
|
22
|
+
attr_reader :edited_at
|
|
23
|
+
|
|
24
|
+
# @return [Integer] the flags that have been set on the message snapshot.
|
|
25
|
+
attr_reader :flags
|
|
26
|
+
|
|
27
|
+
# @return [Array<User>] the users that were mentioned in the message snapshot.
|
|
28
|
+
attr_reader :mentions
|
|
29
|
+
|
|
30
|
+
# @return [Array<Component>] the interaction components associated with the message snapshot.
|
|
31
|
+
attr_reader :components
|
|
32
|
+
|
|
33
|
+
# @!visibility private
|
|
34
|
+
def initialize(data, bot)
|
|
35
|
+
@bot = bot
|
|
36
|
+
@type = data['type']
|
|
37
|
+
@flags = data['flags'] || 0
|
|
38
|
+
@content = data['content']
|
|
39
|
+
@mention_roles = data['mention_roles']&.map(&:resolve_id) || []
|
|
40
|
+
@embeds = data['embeds']&.map { |embed| Embed.new(embed, self) } || []
|
|
41
|
+
@attachments = data['attachments']&.map { |file| Attachment.new(file, self, @bot) } || []
|
|
42
|
+
@created_at = data['timestamp'] ? Time.parse(data['timestamp']) : nil
|
|
43
|
+
@edited_at = data['edited_timestamp'] ? Time.parse(data['edited_timestamp']) : nil
|
|
44
|
+
@mentions = data['mentions']&.map { |mention| @bot.ensure_user(mention) } || []
|
|
45
|
+
@components = data['components']&.map { |component| Components.from_data(component, @bot) } || []
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Check whether the message snapshot has been edited.
|
|
49
|
+
# @return [true, false] whether the snapshot was edited or not.
|
|
50
|
+
def edited?
|
|
51
|
+
!@edited_at.nil?
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Check whether the message snapshot contains any custom emojis.
|
|
55
|
+
# @return [true, false] whether or not any emoji were used in the snapshot.
|
|
56
|
+
def emojis?
|
|
57
|
+
emojis.any?
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Get the custom emojis that were used in the message snapshot.
|
|
61
|
+
# @return [Array<Emoji>] the emojis used in the message snapshot.
|
|
62
|
+
def emojis
|
|
63
|
+
return [] if @content.nil? || @content.empty?
|
|
64
|
+
|
|
65
|
+
@emojis ||= @bot.parse_mentions(@content).select { |parsed| parsed.is_a?(Emoji) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Get the roles that were mentioned in the message snapshot.
|
|
69
|
+
# @return [Array<Role>] the roles that were mentioned in the message snapshot.
|
|
70
|
+
# @note this can only resolve roles in servers that the bot has access to via {Bot#servers}.
|
|
71
|
+
def role_mentions
|
|
72
|
+
return [] if @mention_roles.empty?
|
|
73
|
+
|
|
74
|
+
return @role_mentions if @role_mentions
|
|
75
|
+
|
|
76
|
+
roles = @bot.servers.values.flat_map(&:roles)
|
|
77
|
+
|
|
78
|
+
@role_mentions = @mention_roles.filter_map { |id| roles.find { |r| r.id == id } }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Get the buttons that were used in the message snapshot.
|
|
82
|
+
# @return [Array<Components::Button>] the button components used in the message snapshot.
|
|
83
|
+
def buttons
|
|
84
|
+
buttons = @components.flat_map do |component|
|
|
85
|
+
case component
|
|
86
|
+
when Components::Button
|
|
87
|
+
component
|
|
88
|
+
when Components::Section
|
|
89
|
+
component.accessory if component.accessory.is_a?(Components::Button)
|
|
90
|
+
when Components::ActionRow, Components::Container
|
|
91
|
+
component.buttons
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
buttons.compact
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @see OnyxCord::Message::FLAGS
|
|
99
|
+
Message::FLAGS.each do |name, value|
|
|
100
|
+
define_method("#{name}?") do
|
|
101
|
+
@flags.anybits?(value)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @see OnyxCord::Message::TYPES
|
|
106
|
+
Message::TYPES.each do |name, value|
|
|
107
|
+
define_method("#{name}?") do
|
|
108
|
+
@type == value
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OnyxCord
|
|
4
|
+
# A group of users that can manage applications.
|
|
5
|
+
class Team
|
|
6
|
+
include IDObject
|
|
7
|
+
|
|
8
|
+
# @return [String] the name of this team.
|
|
9
|
+
attr_reader :name
|
|
10
|
+
|
|
11
|
+
# @return [Member] the owner of this team.
|
|
12
|
+
attr_reader :owner
|
|
13
|
+
|
|
14
|
+
# @return [String, nil] the ID of this team's icon.
|
|
15
|
+
# @see #icon_url
|
|
16
|
+
attr_reader :icon_id
|
|
17
|
+
|
|
18
|
+
# @return [Array<Member>] the members that are a part of this team.
|
|
19
|
+
attr_reader :members
|
|
20
|
+
|
|
21
|
+
# @!visibility private
|
|
22
|
+
def initialize(data, bot)
|
|
23
|
+
@bot = bot
|
|
24
|
+
@id = data['id'].to_i
|
|
25
|
+
@name = data['name']
|
|
26
|
+
@icon_id = data['icon']
|
|
27
|
+
@members = data['members'].map { |member| Member.new(member, self, bot) }
|
|
28
|
+
@owner = @members.find { |member| member.user.id == data['owner_user_id'].to_i }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Utility method to get a team's icon URL.
|
|
32
|
+
# @param format [String] The URL will default to `webp`. You can otherwise specify one of `webp`, `jpg`, or `png` to override this.
|
|
33
|
+
# @return [String, nil] the URL to the icon image (nil if no image is set).
|
|
34
|
+
def icon_url(format = 'webp')
|
|
35
|
+
API.team_icon_url(@id, @icon_id, format) if @icon_id
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# A member that has been invited to a team.
|
|
39
|
+
class Member
|
|
40
|
+
# @return [Symbol] the role of this team member.
|
|
41
|
+
attr_reader :role
|
|
42
|
+
|
|
43
|
+
# @return [Team] the team this member is a part of.
|
|
44
|
+
attr_reader :team
|
|
45
|
+
|
|
46
|
+
# @return [Integer] the membership state of this team member.
|
|
47
|
+
attr_reader :state
|
|
48
|
+
|
|
49
|
+
# @return [Integer] the user associated with this team member.
|
|
50
|
+
attr_reader :user
|
|
51
|
+
|
|
52
|
+
# @!visibility private
|
|
53
|
+
def initialize(data, team, bot)
|
|
54
|
+
@bot = bot
|
|
55
|
+
@team = team
|
|
56
|
+
@role = data['role'].to_sym
|
|
57
|
+
@state = data['membership_state']
|
|
58
|
+
@user = bot.ensure_user(data['user'])
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Whether this team member has been invited to the team, but hasn't accepted the invite yet.
|
|
62
|
+
# @return [true, false]
|
|
63
|
+
def pending?
|
|
64
|
+
@state == 1
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Whether this team member is the owner of the team.
|
|
68
|
+
# @return [true, false]
|
|
69
|
+
def owner?
|
|
70
|
+
@team.owner == self
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @!method admin?
|
|
74
|
+
# @return [true, false] whether this team member is an admin.
|
|
75
|
+
# @!method developer?
|
|
76
|
+
# @return [true, false] whether this team member is a developer.
|
|
77
|
+
# @!method read_only?
|
|
78
|
+
# @return [true, false] whether this team member is a read only developer.
|
|
79
|
+
%i[admin developer read_only].each do |role|
|
|
80
|
+
define_method("#{role}?") do
|
|
81
|
+
@role == role
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Comparison based off of user ID and team ID.
|
|
86
|
+
# @return [true, false] if the two objects are equal.
|
|
87
|
+
def ==(other)
|
|
88
|
+
return false unless other.is_a?(Member)
|
|
89
|
+
|
|
90
|
+
return false unless @team == other.team
|
|
91
|
+
|
|
92
|
+
OnyxCord.id_compare?(other.user.id, @user.id)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
alias_method :eql?, :==
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OnyxCord
|
|
4
|
+
# A timestamp referenced in a message via markdown.
|
|
5
|
+
class TimestampMarkdown
|
|
6
|
+
# Mapping of timestamp styles.
|
|
7
|
+
STYLES = {
|
|
8
|
+
short_time: 't', # 16:20
|
|
9
|
+
long_time: 'T', # 16:20:30
|
|
10
|
+
short_date: 'd', # 20/04/2021
|
|
11
|
+
long_date: 'D', # 20 April 2021
|
|
12
|
+
short_datetime: 'f', # 20 April 2021 16:20
|
|
13
|
+
long_datetime: 'F', # Tuesday, 20 April 2021 16:20
|
|
14
|
+
relative: 'R', # 2 months ago
|
|
15
|
+
simple_datetime: 's', # 20/04/2021, 16:20
|
|
16
|
+
medium_datetime: 'S' # 20/04/2021, 16:20:30
|
|
17
|
+
}.freeze
|
|
18
|
+
|
|
19
|
+
# @return [Time] the time that the timestamp is referencing.
|
|
20
|
+
attr_reader :time
|
|
21
|
+
|
|
22
|
+
# @!visibility private
|
|
23
|
+
def initialize(time, style)
|
|
24
|
+
@time = time
|
|
25
|
+
@style = style
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Get the specifier used to determine the style of the timestamp.
|
|
29
|
+
# @return [String] the formatting specifier used to display the timestamp.
|
|
30
|
+
def style
|
|
31
|
+
@style || 'f'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Get a string that will allow you to display the time in the Discord client.
|
|
35
|
+
# @return [String] The timestamp serialized as a string for the Discord client.
|
|
36
|
+
def to_s
|
|
37
|
+
OnyxCord.timestamp(@time, @style)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @!visibility private
|
|
41
|
+
def inspect
|
|
42
|
+
"<TimestampMarkdown time=#{@time.to_i} style=\"#{style}\">"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @!method short_time?
|
|
46
|
+
# @return [true, false] whether or not the timestamp is displayed in a format such as `16:20`.
|
|
47
|
+
# @!method long_time?
|
|
48
|
+
# @return [true, false] whether or not the timestamp is displayed in a format such as `16:20:30`.
|
|
49
|
+
# @!method short_date?
|
|
50
|
+
# @return [true, false] whether or not the timestamp is displayed in a format such as `20/04/2021`.
|
|
51
|
+
# @!method long_date?
|
|
52
|
+
# @return [true, false] whether or not the timestamp is displayed in a format such as `20 April 2021`.
|
|
53
|
+
# @!method short_datetime?
|
|
54
|
+
# @return [true, false] whether or not the timestamp is displayed in a format such as `20 April 2021 16:20`.
|
|
55
|
+
# @!method long_datetime?
|
|
56
|
+
# @return [true, false] whether or not the timestamp is displayed in a format such as `Tuesday, 20 April 2021 16:20`.
|
|
57
|
+
# @!method relative?
|
|
58
|
+
# @return [true, false] whether or not the timestamp is displayed in a format such as `2 months ago`.
|
|
59
|
+
# @!method simple_datetime?
|
|
60
|
+
# @return [true, false] whether or not the timestamp is displayed in a format such as `20/04/2021, 16:20`.
|
|
61
|
+
# @!method medium_datetime?
|
|
62
|
+
# @return [true, false] whether or not the timestamp is displayed in a format such as ` 20/04/2021, 16:20:30`.
|
|
63
|
+
STYLES.each do |name, value|
|
|
64
|
+
define_method("#{name}?") do
|
|
65
|
+
style == value
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OnyxCord
|
|
4
|
+
# Mixin for the attributes users should have
|
|
5
|
+
module UserAttributes
|
|
6
|
+
# rubocop:disable Naming/VariableNumber
|
|
7
|
+
FLAGS = {
|
|
8
|
+
staff: 1 << 0,
|
|
9
|
+
partner: 1 << 1,
|
|
10
|
+
hypesquad: 1 << 2,
|
|
11
|
+
bug_hunter_level_1: 1 << 3,
|
|
12
|
+
hypesquad_online_house_1: 1 << 6,
|
|
13
|
+
hypesquad_online_house_2: 1 << 7,
|
|
14
|
+
hypesquad_online_house_3: 1 << 8,
|
|
15
|
+
premium_early_supporter: 1 << 9,
|
|
16
|
+
team_pseudo_user: 1 << 10,
|
|
17
|
+
bug_hunter_level_2: 1 << 14,
|
|
18
|
+
verified_bot: 1 << 16,
|
|
19
|
+
verified_developer: 1 << 17,
|
|
20
|
+
certified_moderator: 1 << 18,
|
|
21
|
+
bot_http_interactions: 1 << 19,
|
|
22
|
+
active_developer: 1 << 22
|
|
23
|
+
}.freeze
|
|
24
|
+
# rubocop:enable Naming/VariableNumber
|
|
25
|
+
|
|
26
|
+
# @return [String] this user's username
|
|
27
|
+
attr_reader :username
|
|
28
|
+
alias_method :name, :username
|
|
29
|
+
|
|
30
|
+
# @return [String, nil] this user's global name
|
|
31
|
+
attr_reader :global_name
|
|
32
|
+
|
|
33
|
+
# @return [String] this user's discriminator which is used internally to identify users with identical usernames.
|
|
34
|
+
attr_reader :discriminator
|
|
35
|
+
alias_method :discrim, :discriminator
|
|
36
|
+
alias_method :tag, :discriminator
|
|
37
|
+
alias_method :discord_tag, :discriminator
|
|
38
|
+
|
|
39
|
+
# @return [true, false] whether this user is a Discord bot account
|
|
40
|
+
attr_reader :bot_account
|
|
41
|
+
alias_method :bot_account?, :bot_account
|
|
42
|
+
|
|
43
|
+
# @return [true, false] whether this is fake user for a webhook message
|
|
44
|
+
attr_reader :webhook_account
|
|
45
|
+
alias_method :webhook_account?, :webhook_account
|
|
46
|
+
alias_method :webhook?, :webhook_account
|
|
47
|
+
|
|
48
|
+
# @return [String] the ID of this user's current avatar, can be used to generate an avatar URL.
|
|
49
|
+
# @see #avatar_url
|
|
50
|
+
attr_accessor :avatar_id
|
|
51
|
+
|
|
52
|
+
# @return [true, false] whether the user is an offical Discord System user (part of the urgent message system).
|
|
53
|
+
attr_reader :system_account
|
|
54
|
+
alias_method :system_account?, :system_account
|
|
55
|
+
|
|
56
|
+
# @return [AvatarDecoration, nil] the current user's avatar decoration, or nil if the user doesn't have one.
|
|
57
|
+
attr_reader :avatar_decoration
|
|
58
|
+
|
|
59
|
+
# @return [Collectibles] the collectibles that this user has collected.
|
|
60
|
+
attr_reader :collectibles
|
|
61
|
+
|
|
62
|
+
# @return [PrimaryServer, nil] the server tag the user has adopted, or nil if the user doesn't have one displayed.
|
|
63
|
+
attr_reader :primary_server
|
|
64
|
+
alias_method :server_tag, :primary_server
|
|
65
|
+
|
|
66
|
+
# Utility function to get Discord's display name of a user not in server
|
|
67
|
+
# @return [String] the name the user displays as (global_name if they have one, username otherwise)
|
|
68
|
+
def display_name
|
|
69
|
+
global_name || username
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Utility function to mention users in messages
|
|
73
|
+
# @return [String] the mention code in the form of <@id>
|
|
74
|
+
def mention
|
|
75
|
+
"<@#{@id}>"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Utility function to get Discord's distinct representation of a user, i.e. username + discriminator
|
|
79
|
+
# @return [String] distinct representation of user
|
|
80
|
+
# TODO: Maybe change this method again after discriminator removal ?
|
|
81
|
+
def distinct
|
|
82
|
+
if @discriminator && @discriminator != '0'
|
|
83
|
+
"#{@username}##{@discriminator}"
|
|
84
|
+
else
|
|
85
|
+
@username.to_s
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Utility function to get a user's avatar URL.
|
|
90
|
+
# @param format [String, nil] If `nil`, the URL will default to `webp` for static avatars, and will detect if the user has a `gif` avatar. You can otherwise specify one of `webp`, `jpg`, `png`, or `gif` to override this. Will always be PNG for default avatars.
|
|
91
|
+
# @return [String] the URL to the avatar image.
|
|
92
|
+
# TODO: Maybe change this method again after discriminator removal ?
|
|
93
|
+
def avatar_url(format = nil)
|
|
94
|
+
unless @avatar_id
|
|
95
|
+
return API::User.default_avatar(@discriminator, legacy: true) if @discriminator && @discriminator != '0'
|
|
96
|
+
|
|
97
|
+
return API::User.default_avatar(@id)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
API::User.avatar_url(@id, @avatar_id, format)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# @return [Integer] the public flags on a user's account
|
|
104
|
+
attr_reader :public_flags
|
|
105
|
+
|
|
106
|
+
FLAGS.each do |name, value|
|
|
107
|
+
define_method("#{name}?") do
|
|
108
|
+
@public_flags.anybits?(value)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Utility function to get a user's banner URL.
|
|
113
|
+
# @param format [String, nil] If `nil`, the URL will default to `png` for static banners and will detect if the user has a `gif` banner.
|
|
114
|
+
# You can otherwise specify one of `webp`, `jpg`, `png`, or `gif` to override this.
|
|
115
|
+
# @return [String, nil] the URL to the banner image or nil if the user doesn't have one.
|
|
116
|
+
def banner_url(format = nil)
|
|
117
|
+
API::User.banner_url(@id, banner_id, format) if banner_id
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# User on Discord, including internal data like discriminators
|
|
122
|
+
class User
|
|
123
|
+
include IDObject
|
|
124
|
+
include UserAttributes
|
|
125
|
+
|
|
126
|
+
# @return [Symbol] the current online status of the user (`:online`, `:offline` or `:idle`)
|
|
127
|
+
attr_reader :status
|
|
128
|
+
|
|
129
|
+
# @return [ActivitySet] the activities of the user
|
|
130
|
+
attr_reader :activities
|
|
131
|
+
|
|
132
|
+
# @return [Hash<Symbol, Symbol>] the current online status (`:online`, `:idle` or `:dnd`) of the user
|
|
133
|
+
# on various device types (`:desktop`, `:mobile`, or `:web`). The value will be `nil` if the user is offline or invisible.
|
|
134
|
+
attr_reader :client_status
|
|
135
|
+
|
|
136
|
+
# @!visibility private
|
|
137
|
+
def initialize(data, bot)
|
|
138
|
+
@bot = bot
|
|
139
|
+
|
|
140
|
+
@username = data['username']
|
|
141
|
+
@global_name = data['global_name']
|
|
142
|
+
@id = data['id'].to_i
|
|
143
|
+
@discriminator = data['discriminator']
|
|
144
|
+
@avatar_id = data['avatar']
|
|
145
|
+
@activities = OnyxCord::ActivitySet.new
|
|
146
|
+
@public_flags = data['public_flags'] || 0
|
|
147
|
+
@bot_account = data['bot'] || false
|
|
148
|
+
@webhook_account = data['_webhook'] || false
|
|
149
|
+
|
|
150
|
+
@status = :offline
|
|
151
|
+
@client_status = process_client_status(data['client_status'])
|
|
152
|
+
@banner_id = data['banner']
|
|
153
|
+
@system_account = data['system'] || false
|
|
154
|
+
@avatar_decoration = process_avatar_decoration(data['avatar_decoration_data'])
|
|
155
|
+
@collectibles = Collectibles.new(data['collectibles'] || {}, bot)
|
|
156
|
+
|
|
157
|
+
@primary_server = process_primary_server(data['primary_guild'] || {})
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Get a user's PM channel or send them a PM
|
|
161
|
+
# @overload pm
|
|
162
|
+
# Creates a private message channel for this user or returns an existing one if it already exists
|
|
163
|
+
# @return [Channel] the PM channel to this user.
|
|
164
|
+
# @overload pm(content)
|
|
165
|
+
# Sends a private to this user.
|
|
166
|
+
# @param content [String] The content to send.
|
|
167
|
+
# @return [Message] the message sent to this user.
|
|
168
|
+
def pm(content = nil)
|
|
169
|
+
if content
|
|
170
|
+
# Recursively call pm to get the channel, then send a message to it
|
|
171
|
+
channel = pm
|
|
172
|
+
channel.send_message(content)
|
|
173
|
+
else
|
|
174
|
+
# If no message was specified, return the PM channel
|
|
175
|
+
@bot.pm_channel(@id)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
alias_method :dm, :pm
|
|
180
|
+
|
|
181
|
+
# Send the user a file.
|
|
182
|
+
# @param file [File] The file to send to the user
|
|
183
|
+
# @param caption [String] The caption of the file being sent
|
|
184
|
+
# @param filename [String] Overrides the filename of the uploaded file
|
|
185
|
+
# @param spoiler [true, false] Whether or not this file should appear as a spoiler.
|
|
186
|
+
# @return [Message] the message sent to this user.
|
|
187
|
+
# @example Send a file from disk
|
|
188
|
+
# user.send_file(File.open('rubytaco.png', 'r'))
|
|
189
|
+
def send_file(file, caption = nil, filename: nil, spoiler: nil)
|
|
190
|
+
pm.send_file(file, caption: caption, filename: filename, spoiler: spoiler)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# @return [String, nil] the ID of this user's current banner, can be used to generate a banner URL.
|
|
194
|
+
# @see #banner_url
|
|
195
|
+
def banner_id
|
|
196
|
+
@banner_id ||= JSON.parse(API::User.resolve(@bot.token, @id))['banner']
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Set the user's username
|
|
200
|
+
# @note for internal use only
|
|
201
|
+
# @!visibility private
|
|
202
|
+
def update_username(username)
|
|
203
|
+
@username = username
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Set the user's global_name
|
|
207
|
+
# @note For internal use only.
|
|
208
|
+
# @!visibility private
|
|
209
|
+
def update_global_name(global_name)
|
|
210
|
+
@global_name = global_name
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Set the user's avatar_decoration
|
|
214
|
+
# @note For internal use only.
|
|
215
|
+
# @!visibility private
|
|
216
|
+
def update_avatar_decoration(decoration)
|
|
217
|
+
@avatar_decoration = process_avatar_decoration(decoration)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Set the user's collectibles
|
|
221
|
+
# @note For internal use only.
|
|
222
|
+
# @!visibility private
|
|
223
|
+
def update_collectibles(collectibles)
|
|
224
|
+
@collectibles = Collectibles.new(collectibles || {}, @bot)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Set the user's primary server
|
|
228
|
+
# @note For internal use only.
|
|
229
|
+
# @!visibility private
|
|
230
|
+
def update_primary_server(server)
|
|
231
|
+
@primary_server = process_primary_server(server || {})
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# Set the user's presence data
|
|
235
|
+
# @note for internal use only
|
|
236
|
+
# @!visibility private
|
|
237
|
+
def update_presence(data)
|
|
238
|
+
@status = data['status'].to_sym
|
|
239
|
+
@client_status = process_client_status(data['client_status'])
|
|
240
|
+
|
|
241
|
+
@activities = OnyxCord::ActivitySet.new(data['activities'].map { |act| Activity.new(act, @bot) })
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Add an await for a message from this user. Specifically, this adds a global await for a MessageEvent with this
|
|
245
|
+
# user's ID as a :from attribute.
|
|
246
|
+
# @see Bot#add_await
|
|
247
|
+
def await(key, attributes = {}, &block)
|
|
248
|
+
@bot.add_await(key, OnyxCord::Events::MessageEvent, { from: @id }.merge(attributes), &block)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Add a blocking await for a message from this user. Specifically, this adds a global await for a MessageEvent with this
|
|
252
|
+
# user's ID as a :from attribute.
|
|
253
|
+
# @see Bot#add_await!
|
|
254
|
+
def await!(attributes = {}, &block)
|
|
255
|
+
@bot.add_await!(OnyxCord::Events::MessageEvent, { from: @id }.merge(attributes), &block)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Gets the member this user is on a server
|
|
259
|
+
# @param server [Server] The server to get the member for
|
|
260
|
+
# @return [Member] this user as a member on a particular server
|
|
261
|
+
def on(server)
|
|
262
|
+
id = server.resolve_id
|
|
263
|
+
@bot.server(id).member(@id)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Is the user the bot?
|
|
267
|
+
# @return [true, false] whether this user is the bot
|
|
268
|
+
def current_bot?
|
|
269
|
+
@bot.profile.id == @id
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# @!visibility private
|
|
273
|
+
def process_client_status(client_status)
|
|
274
|
+
(client_status || {}).to_h { |k, v| [k.to_sym, v.to_sym] }
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# @!visibility private
|
|
278
|
+
def process_avatar_decoration(decoration)
|
|
279
|
+
decoration ? AvatarDecoration.new(decoration, @bot) : nil
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# @!visibility private
|
|
283
|
+
def process_primary_server(server)
|
|
284
|
+
PrimaryServer.new(server, @bot) if server['identity_enabled']
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# @!method offline?
|
|
288
|
+
# @return [true, false] whether this user is offline.
|
|
289
|
+
# @!method idle?
|
|
290
|
+
# @return [true, false] whether this user is idle.
|
|
291
|
+
# @!method online?
|
|
292
|
+
# @return [true, false] whether this user is online.
|
|
293
|
+
# @!method dnd?
|
|
294
|
+
# @return [true, false] whether this user is set to do not disturb.
|
|
295
|
+
%i[offline idle online dnd].each do |e|
|
|
296
|
+
define_method("#{e}?") do
|
|
297
|
+
@status.to_sym == e
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# @return [String, nil] the game the user is currently playing, or `nil` if nothing is being played.
|
|
302
|
+
# @deprecated Please use {ActivitySet#games} for information about the user's game activity
|
|
303
|
+
def game
|
|
304
|
+
@activities.games.first&.name
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# @return [Integer] returns 1 for twitch streams, or 0 for no stream.
|
|
308
|
+
# @deprecated Please use {ActivitySet#streaming} for information about the user's stream activity
|
|
309
|
+
def stream_type
|
|
310
|
+
@activities.streaming ? 1 : 0
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
# @return [String, nil] the URL to the stream, if the user is currently streaming something
|
|
314
|
+
# @deprecated Please use {ActivitySet#streaming} for information about the user's stream activity
|
|
315
|
+
def stream_url
|
|
316
|
+
@activities.streaming.first&.url
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# The inspect method is overwritten to give more useful output
|
|
320
|
+
def inspect
|
|
321
|
+
"<User username=#{@username} id=#{@id} discriminator=#{@discriminator}>"
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
end
|