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,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OnyxCord
|
|
4
|
+
# A channel referenced by an invite. It has less data than regular channels, so it's a separate class
|
|
5
|
+
class InviteChannel
|
|
6
|
+
include IDObject
|
|
7
|
+
|
|
8
|
+
# @return [String] this channel's name.
|
|
9
|
+
attr_reader :name
|
|
10
|
+
|
|
11
|
+
# @return [Integer] this channel's type (0: text, 1: private, 2: voice, 3: group).
|
|
12
|
+
attr_reader :type
|
|
13
|
+
|
|
14
|
+
# @!visibility private
|
|
15
|
+
def initialize(data, bot)
|
|
16
|
+
@bot = bot
|
|
17
|
+
|
|
18
|
+
@id = data['id'].to_i
|
|
19
|
+
@name = data['name']
|
|
20
|
+
@type = data['type']
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# A server referenced to by an invite
|
|
25
|
+
class InviteServer
|
|
26
|
+
include IDObject
|
|
27
|
+
|
|
28
|
+
# @return [String] this server's name.
|
|
29
|
+
attr_reader :name
|
|
30
|
+
|
|
31
|
+
# @return [String, nil] the hash of the server's invite splash screen (for partnered servers) or nil if none is
|
|
32
|
+
# present
|
|
33
|
+
attr_reader :splash_hash
|
|
34
|
+
|
|
35
|
+
# @!visibility private
|
|
36
|
+
def initialize(data, bot)
|
|
37
|
+
@bot = bot
|
|
38
|
+
|
|
39
|
+
@id = data['id'].to_i
|
|
40
|
+
@name = data['name']
|
|
41
|
+
@splash_hash = data['splash_hash']
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# A Discord invite to a channel
|
|
46
|
+
class Invite
|
|
47
|
+
# @return [InviteChannel, Channel] the channel this invite references.
|
|
48
|
+
attr_reader :channel
|
|
49
|
+
|
|
50
|
+
# @return [InviteServer, Server] the server this invite references.
|
|
51
|
+
attr_reader :server
|
|
52
|
+
|
|
53
|
+
# @return [Integer] the amount of uses left on this invite.
|
|
54
|
+
attr_reader :uses
|
|
55
|
+
alias_method :max_uses, :uses
|
|
56
|
+
|
|
57
|
+
# @return [User, nil] the user that made this invite. May also be nil if the user can't be determined.
|
|
58
|
+
attr_reader :inviter
|
|
59
|
+
alias_method :user, :inviter
|
|
60
|
+
|
|
61
|
+
# @return [true, false] whether or not this invite grants temporary membership. If someone joins a server with this invite, they will be removed from the server when they go offline unless they've received a role.
|
|
62
|
+
attr_reader :temporary
|
|
63
|
+
alias_method :temporary?, :temporary
|
|
64
|
+
|
|
65
|
+
# @return [true, false] whether this invite is still valid.
|
|
66
|
+
attr_reader :revoked
|
|
67
|
+
alias_method :revoked?, :revoked
|
|
68
|
+
|
|
69
|
+
# @return [String] this invite's code
|
|
70
|
+
attr_reader :code
|
|
71
|
+
|
|
72
|
+
# @return [Integer, nil] the amount of members in the server. Will be nil if it has not been resolved.
|
|
73
|
+
attr_reader :member_count
|
|
74
|
+
alias_method :user_count, :member_count
|
|
75
|
+
|
|
76
|
+
# @return [Integer, nil] the amount of online members in the server. Will be nil if it has not been resolved.
|
|
77
|
+
attr_reader :online_member_count
|
|
78
|
+
alias_method :online_user_count, :online_member_count
|
|
79
|
+
|
|
80
|
+
# @return [Integer, nil] the invites max age before it expires, or nil if it's unknown. If the max age is 0, the invite will never expire unless it's deleted.
|
|
81
|
+
attr_reader :max_age
|
|
82
|
+
|
|
83
|
+
# @return [Time, nil] when this invite was created, or nil if it's unknown
|
|
84
|
+
attr_reader :created_at
|
|
85
|
+
|
|
86
|
+
# @!visibility private
|
|
87
|
+
def initialize(data, bot)
|
|
88
|
+
@bot = bot
|
|
89
|
+
|
|
90
|
+
@channel = if data['channel_id']
|
|
91
|
+
bot.channel(data['channel_id'])
|
|
92
|
+
else
|
|
93
|
+
InviteChannel.new(data['channel'], bot)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
@server = if data['guild_id']
|
|
97
|
+
bot.server(data['guild_id'])
|
|
98
|
+
else
|
|
99
|
+
InviteServer.new(data['guild'], bot)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
@uses = data['uses']
|
|
103
|
+
@inviter = data['inviter'] ? bot.ensure_user(data['inviter']) : nil
|
|
104
|
+
@temporary = data['temporary']
|
|
105
|
+
@revoked = data['revoked']
|
|
106
|
+
@online_member_count = data['approximate_presence_count']
|
|
107
|
+
@member_count = data['approximate_member_count']
|
|
108
|
+
@max_age = data['max_age']
|
|
109
|
+
@created_at = data['created_at']
|
|
110
|
+
|
|
111
|
+
@code = data['code']
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Code based comparison
|
|
115
|
+
def ==(other)
|
|
116
|
+
other.respond_to?(:code) ? (@code == other.code) : (@code == other)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Deletes this invite
|
|
120
|
+
# @param reason [String] The reason the invite is being deleted.
|
|
121
|
+
def delete(reason = nil)
|
|
122
|
+
API::Invite.delete(@bot.token, @code, reason)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
alias_method :revoke, :delete
|
|
126
|
+
|
|
127
|
+
# The inspect method is overwritten to give more useful output
|
|
128
|
+
def inspect
|
|
129
|
+
"<Invite code=#{@code} channel=#{@channel} uses=#{@uses} temporary=#{@temporary} revoked=#{@revoked} created_at=#{@created_at} max_age=#{@max_age}>"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Creates an invite URL.
|
|
133
|
+
def url
|
|
134
|
+
"https://discord.gg/#{@code}"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OnyxCord
|
|
4
|
+
# Mixin for the attributes members and private members should have
|
|
5
|
+
module MemberAttributes
|
|
6
|
+
# Map of server member flags
|
|
7
|
+
MEMBER_FLAGS = {
|
|
8
|
+
rejoined: 1 << 0,
|
|
9
|
+
completed_onboarding: 1 << 1,
|
|
10
|
+
bypassed_verification: 1 << 2,
|
|
11
|
+
started_onboarding: 1 << 3,
|
|
12
|
+
guest: 1 << 4,
|
|
13
|
+
started_home_actions: 1 << 5,
|
|
14
|
+
completed_home_actions: 1 << 6,
|
|
15
|
+
automod_quarantined_username: 1 << 7,
|
|
16
|
+
dm_settings_upsell_acknowledged: 1 << 9,
|
|
17
|
+
automod_quarantined_server_tag: 1 << 10
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
# @return [Time] when this member joined the server.
|
|
21
|
+
attr_reader :joined_at
|
|
22
|
+
|
|
23
|
+
# @return [Time, nil] when this member boosted this server, `nil` if they haven't.
|
|
24
|
+
attr_reader :boosting_since
|
|
25
|
+
|
|
26
|
+
# @return [String, nil] the nickname this member has, or `nil` if it has none.
|
|
27
|
+
attr_reader :nick
|
|
28
|
+
alias_method :nickname, :nick
|
|
29
|
+
|
|
30
|
+
# @return [Array<Role>] the roles this member has.
|
|
31
|
+
attr_reader :roles
|
|
32
|
+
|
|
33
|
+
# @return [Server] the server this member is on.
|
|
34
|
+
attr_reader :server
|
|
35
|
+
|
|
36
|
+
# @return [Time] When the user's timeout will expire.
|
|
37
|
+
attr_reader :communication_disabled_until
|
|
38
|
+
alias_method :timeout, :communication_disabled_until
|
|
39
|
+
|
|
40
|
+
# @return [Integer] the flags set on this member.
|
|
41
|
+
attr_reader :flags
|
|
42
|
+
|
|
43
|
+
# @return [true, false] whether the member has not yet passed the server's membership screening requirements.
|
|
44
|
+
attr_reader :pending
|
|
45
|
+
alias_method :pending?, :pending
|
|
46
|
+
|
|
47
|
+
# @return [String, nil] the ID of this user's current avatar, can be used to generate a server avatar URL.
|
|
48
|
+
# @see #server_avatar_url
|
|
49
|
+
attr_reader :server_avatar_id
|
|
50
|
+
|
|
51
|
+
# @return [String, nil] the ID of this user's current server banner, can be used to generate a banner URL.
|
|
52
|
+
# @see #server_banner_url
|
|
53
|
+
attr_reader :server_banner_id
|
|
54
|
+
|
|
55
|
+
# @return [AvatarDecoration, nil] the user's current server avatar decoration, or nil for no server avatar decoration.
|
|
56
|
+
attr_reader :server_avatar_decoration
|
|
57
|
+
|
|
58
|
+
# @return [Collectibles] the server-specific collectibles that this user has collected.
|
|
59
|
+
attr_reader :server_collectibles
|
|
60
|
+
|
|
61
|
+
# Utility method to get a member's server avatar URL.
|
|
62
|
+
# @param format [String, nil] If `nil`, the URL will default to `webp` for static avatars, and will detect if the member has a `gif` avatar. You can otherwise specify one of `webp`, `jpg`, `png`, or `gif` to override this.
|
|
63
|
+
# @return [String, nil] the URL to the avatar image, or nil if the member doesn't have one.
|
|
64
|
+
def server_avatar_url(format = nil)
|
|
65
|
+
API::Server.avatar_url(@server_id, @user.id, @server_avatar_id, format) if @server_avatar_id
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Utility method to get a member's server banner URL.
|
|
69
|
+
# @param format [String, nil] If `nil`, the URL will default to `webp` for static banners, and will detect if the member has a `gif` banner. You can otherwise specify one of `webp`, `jpg`, `png`, or `gif` to override this.
|
|
70
|
+
# @return [String, nil] the URL to the banner image, or nil if the member doesn't have one.
|
|
71
|
+
def server_banner_url(format = nil)
|
|
72
|
+
API::Server.banner_url(@server_id, @user.id, @server_banner_id, format) if @server_banner_id
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
MEMBER_FLAGS.each do |name, value|
|
|
76
|
+
define_method("#{name}?") do
|
|
77
|
+
@flags.anybits?(value)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# A member is a user on a server. It differs from regular users in that it has roles, voice statuses and things like
|
|
83
|
+
# that.
|
|
84
|
+
class Member < DelegateClass(User)
|
|
85
|
+
# @return [true, false] whether this member is muted server-wide.
|
|
86
|
+
def mute
|
|
87
|
+
voice_state_attribute(:mute)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# @return [true, false] whether this member is deafened server-wide.
|
|
91
|
+
def deaf
|
|
92
|
+
voice_state_attribute(:deaf)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @return [true, false] whether this member has muted themselves.
|
|
96
|
+
def self_mute
|
|
97
|
+
voice_state_attribute(:self_mute)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# @return [true, false] whether this member has deafened themselves.
|
|
101
|
+
def self_deaf
|
|
102
|
+
voice_state_attribute(:self_deaf)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# @return [Channel] the voice channel this member is in.
|
|
106
|
+
def voice_channel
|
|
107
|
+
voice_state_attribute(:voice_channel)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
alias_method :muted?, :mute
|
|
111
|
+
alias_method :deafened?, :deaf
|
|
112
|
+
alias_method :self_muted?, :self_mute
|
|
113
|
+
alias_method :self_deafened?, :self_deaf
|
|
114
|
+
|
|
115
|
+
include MemberAttributes
|
|
116
|
+
|
|
117
|
+
# @!visibility private
|
|
118
|
+
def initialize(data, server, bot)
|
|
119
|
+
@bot = bot
|
|
120
|
+
|
|
121
|
+
@user = bot.ensure_user(data['user'])
|
|
122
|
+
super(@user) # Initialize the delegate class
|
|
123
|
+
|
|
124
|
+
@server = server
|
|
125
|
+
@server_id = server&.id || data['guild_id'].to_i
|
|
126
|
+
|
|
127
|
+
@role_ids = data['roles']&.map(&:to_i) || []
|
|
128
|
+
|
|
129
|
+
@nick = data['nick']
|
|
130
|
+
@joined_at = data['joined_at'] ? Time.parse(data['joined_at']) : nil
|
|
131
|
+
@boosting_since = data['premium_since'] ? Time.parse(data['premium_since']) : nil
|
|
132
|
+
timeout_until = data['communication_disabled_until']
|
|
133
|
+
@communication_disabled_until = timeout_until ? Time.parse(timeout_until) : nil
|
|
134
|
+
@permissions = Permissions.new(data['permissions']) if data['permissions']
|
|
135
|
+
@server_avatar_id = data['avatar']
|
|
136
|
+
@server_banner_id = data['banner']
|
|
137
|
+
@flags = data['flags'] || 0
|
|
138
|
+
@pending = data.key?('pending') ? data['pending'] : false
|
|
139
|
+
@server_avatar_decoration = process_avatar_decoration(data['avatar_decoration_data'])
|
|
140
|
+
@server_collectibles = Collectibles.new(data['collectibles'] || {}, @bot)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# @return [Server] the server this member is on.
|
|
144
|
+
# @raise [OnyxCord::Errors::NoPermission] This can happen when receiving interactions for servers in which the bot is not
|
|
145
|
+
# authorized with the `bot` scope.
|
|
146
|
+
def server
|
|
147
|
+
return @server if @server
|
|
148
|
+
|
|
149
|
+
@server = @bot.server(@server_id)
|
|
150
|
+
raise OnyxCord::Errors::NoPermission, 'The bot does not have access to this server' unless @server
|
|
151
|
+
|
|
152
|
+
@server
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# @return [Array<Role>] the roles this member has.
|
|
156
|
+
# @raise [OnyxCord::Errors::NoPermission] This can happen when receiving interactions for servers in which the bot is not
|
|
157
|
+
# authorized with the `bot` scope.
|
|
158
|
+
def roles
|
|
159
|
+
return @roles if @roles
|
|
160
|
+
|
|
161
|
+
update_roles(@role_ids)
|
|
162
|
+
@roles
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# @return [true, false] if this user is a Nitro Booster of this server.
|
|
166
|
+
def boosting?
|
|
167
|
+
!@boosting_since.nil?
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# @return [true, false] whether this member is the server owner.
|
|
171
|
+
def owner?
|
|
172
|
+
server.owner == self
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# @param role [Role, String, Integer] the role to check or its ID.
|
|
176
|
+
# @return [true, false] whether this member has the specified role.
|
|
177
|
+
def role?(role)
|
|
178
|
+
role = role.resolve_id
|
|
179
|
+
roles.any?(role)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# @see Member#set_roles
|
|
183
|
+
def roles=(role)
|
|
184
|
+
set_roles(role)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Check if the current user has communication disabled.
|
|
188
|
+
# @return [true, false]
|
|
189
|
+
def communication_disabled?
|
|
190
|
+
!@communication_disabled_until.nil? && @communication_disabled_until > Time.now
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
alias_method :timeout?, :communication_disabled?
|
|
194
|
+
|
|
195
|
+
# Set a user's timeout duration, or remove it by setting the timeout to `nil`.
|
|
196
|
+
# @param timeout_until [Time, nil] When the timeout will end.
|
|
197
|
+
def communication_disabled_until=(timeout_until)
|
|
198
|
+
raise ArgumentError, 'A time out cannot exceed 28 days' if timeout_until && timeout_until > (Time.now + 2_419_200)
|
|
199
|
+
|
|
200
|
+
update_member_data(communication_disabled_until: timeout_until&.iso8601)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
alias_method :timeout=, :communication_disabled_until=
|
|
204
|
+
|
|
205
|
+
# Bulk sets a member's roles.
|
|
206
|
+
# @param role [Role, Array<Role>] The role(s) to set.
|
|
207
|
+
# @param reason [String] The reason the user's roles are being changed.
|
|
208
|
+
def set_roles(role, reason = nil)
|
|
209
|
+
role_ids = role_id_array(role)
|
|
210
|
+
update_member_data(roles: role_ids, reason: reason)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Adds and removes roles from a member.
|
|
214
|
+
# @param add [Role, Array<Role>] The role(s) to add.
|
|
215
|
+
# @param remove [Role, Array<Role>] The role(s) to remove.
|
|
216
|
+
# @param reason [String] The reason the user's roles are being changed.
|
|
217
|
+
# @example Remove the 'Member' role from a user, and add the 'Muted' role to them.
|
|
218
|
+
# to_add = server.roles.find {|role| role.name == 'Muted'}
|
|
219
|
+
# to_remove = server.roles.find {|role| role.name == 'Member'}
|
|
220
|
+
# member.modify_roles(to_add, to_remove)
|
|
221
|
+
def modify_roles(add, remove, reason = nil)
|
|
222
|
+
add_role_ids = role_id_array(add)
|
|
223
|
+
remove_role_ids = role_id_array(remove)
|
|
224
|
+
old_role_ids = resolve_role_ids
|
|
225
|
+
new_role_ids = (old_role_ids - remove_role_ids + add_role_ids).uniq
|
|
226
|
+
|
|
227
|
+
update_member_data(roles: new_role_ids, reason: reason)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Adds one or more roles to this member.
|
|
231
|
+
# @param role [Role, Array<Role, String, Integer>, String, Integer] The role(s), or their ID(s), to add.
|
|
232
|
+
# @param reason [String] The reason the user's roles are being changed.
|
|
233
|
+
def add_role(role, reason = nil)
|
|
234
|
+
role_ids = role_id_array(role)
|
|
235
|
+
|
|
236
|
+
if role_ids.one?
|
|
237
|
+
API::Server.add_member_role(@bot.token, @server_id, @user.id, role_ids[0], reason)
|
|
238
|
+
else
|
|
239
|
+
old_role_ids = resolve_role_ids
|
|
240
|
+
new_role_ids = (old_role_ids + role_ids).uniq
|
|
241
|
+
update_member_data(roles: new_role_ids, reason: reason)
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Removes one or more roles from this member.
|
|
246
|
+
# @param role [Role, Array<Role>] The role(s) to remove.
|
|
247
|
+
# @param reason [String] The reason the user's roles are being changed.
|
|
248
|
+
def remove_role(role, reason = nil)
|
|
249
|
+
role_ids = role_id_array(role)
|
|
250
|
+
|
|
251
|
+
if role_ids.one?
|
|
252
|
+
API::Server.remove_member_role(@bot.token, @server_id, @user.id, role_ids[0], reason)
|
|
253
|
+
else
|
|
254
|
+
old_role_ids = resolve_role_ids
|
|
255
|
+
new_role_ids = old_role_ids.reject { |i| role_ids.include?(i) }
|
|
256
|
+
update_member_data(roles: new_role_ids, reason: reason)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# @return [Role] the highest role this member has.
|
|
261
|
+
def highest_role
|
|
262
|
+
roles.max_by(&:position)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# @return [Role, nil] the role this member is being hoisted with.
|
|
266
|
+
def hoist_role
|
|
267
|
+
hoisted_roles = roles.select(&:hoist)
|
|
268
|
+
return nil if hoisted_roles.empty?
|
|
269
|
+
|
|
270
|
+
hoisted_roles.max_by(&:position)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# @return [Role, nil] the role this member is basing their colour on.
|
|
274
|
+
def colour_role
|
|
275
|
+
coloured_roles = roles.select { |v| v.colour.combined.nonzero? }
|
|
276
|
+
return nil if coloured_roles.empty?
|
|
277
|
+
|
|
278
|
+
coloured_roles.max_by(&:position)
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
alias_method :color_role, :colour_role
|
|
282
|
+
|
|
283
|
+
# @return [ColourRGB, nil] the colour this member has.
|
|
284
|
+
def colour
|
|
285
|
+
return nil unless colour_role
|
|
286
|
+
|
|
287
|
+
colour_role.color
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
alias_method :color, :colour
|
|
291
|
+
|
|
292
|
+
# Get the member's roles sorted by their order in the hierarchy.
|
|
293
|
+
# @return [Array<Role>] the roles the member has, ordered by hierarchy.
|
|
294
|
+
def sort_roles
|
|
295
|
+
roles.sort_by { |role| [role.position, role.id] }
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# Server deafens this member.
|
|
299
|
+
# @param reason [String, nil] The reason for defeaning this member.
|
|
300
|
+
def server_deafen(reason: nil)
|
|
301
|
+
update_member_data(deaf: true, reason: reason)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# Server undeafens this member.
|
|
305
|
+
# @param reason [String, nil] The reason for un-defeaning this member.
|
|
306
|
+
def server_undeafen(reason: nil)
|
|
307
|
+
update_member_data(deaf: false, reason: reason)
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Server mutes this member.
|
|
311
|
+
# @param reason [String, nil] The reason for muting this member.
|
|
312
|
+
def server_mute(reason: nil)
|
|
313
|
+
update_member_data(mute: true, reason: reason)
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# Server unmutes this member.
|
|
317
|
+
# @param reason [String, nil] The reason for un-muting this member.
|
|
318
|
+
def server_unmute(reason: nil)
|
|
319
|
+
update_member_data(mute: false, reason: reason)
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Bans this member from the server.
|
|
323
|
+
# @param message_days [Integer] How many days worth of messages sent by the member should be deleted. This parameter is deprecated and will be removed in 4.0.
|
|
324
|
+
# @param message_seconds [Integer] How many seconds worth of messages sent by the member should be deleted.
|
|
325
|
+
# @param reason [String] The reason this member is being banned.
|
|
326
|
+
def ban(message_days = 0, message_seconds: nil, reason: nil)
|
|
327
|
+
server.ban(@user, message_days, message_seconds: message_seconds, reason: reason)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# Unbans this member from the server.
|
|
331
|
+
# @param reason [String] The reason this member is being unbanned.
|
|
332
|
+
def unban(reason = nil)
|
|
333
|
+
server.unban(@user, reason)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# Kicks this member from the server.
|
|
337
|
+
# @param reason [String] The reason this member is being kicked.
|
|
338
|
+
def kick(reason = nil)
|
|
339
|
+
server.kick(@user, reason)
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# @see Member#set_nick
|
|
343
|
+
def nick=(nick)
|
|
344
|
+
set_nick(nick)
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
alias_method :nickname=, :nick=
|
|
348
|
+
|
|
349
|
+
# Sets or resets this member's nickname. Requires the Change Nickname permission for the bot itself and Manage
|
|
350
|
+
# Nicknames for other users.
|
|
351
|
+
# @param nick [String, nil] The string to set the nickname to, or nil if it should be reset.
|
|
352
|
+
# @param reason [String] The reason the user's nickname is being changed.
|
|
353
|
+
def set_nick(nick, reason = nil)
|
|
354
|
+
if @user.current_bot?
|
|
355
|
+
update_current_member_data(nick: nick, reason: reason)
|
|
356
|
+
else
|
|
357
|
+
update_member_data(nick: nick, reason: reason)
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
alias_method :set_nickname, :set_nick
|
|
362
|
+
|
|
363
|
+
# @return [String] the name the user displays as (nickname if they have one, global_name if they have one, username otherwise)
|
|
364
|
+
def display_name
|
|
365
|
+
nickname || global_name || username
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# @param format [String, nil] If `nil`, the URL will default to `webp` for static avatars, and will detect if the member has a `gif` avatar. You can otherwise specify one of `webp`, `jpg`, `png`, or `gif` to override this.
|
|
369
|
+
# @return [String, nil] the avatar that the user has displayed (server avatar if they have one, user avatar if they have one, nil otherwise)
|
|
370
|
+
def display_avatar_url(format = nil)
|
|
371
|
+
server_avatar_url(format) || avatar_url(format)
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# @param format [String, nil] If `nil`, the URL will default to `webp` for static banners, and will detect if the member has a `gif` banner. You can otherwise specify one of `webp`, `jpg`, `png`, or `gif` to override this.
|
|
375
|
+
# @return [String, nil] the banner that the user has displayed (server banner if they have one, user banner if they have one, nil otherwise)
|
|
376
|
+
def display_banner_url(format = nil)
|
|
377
|
+
server_banner_url(format) || banner_url(format)
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# @return [AvatarDecoration, nil] the avatar decoration that the user displays (server avatar decoration if they have one, user avatar decoration if they have one, nil otherwise)
|
|
381
|
+
def display_avatar_decoration
|
|
382
|
+
server_avatar_decoration || avatar_decoration
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
# Set the flags for this member.
|
|
386
|
+
# @param flags [Integer, nil] The new bitwise value of flags for this member, or nil.
|
|
387
|
+
def flags=(flags)
|
|
388
|
+
update_member_data(flags: flags)
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# Set the server banner for the current bot.
|
|
392
|
+
# @param banner [File, nil] A file like object that responds to read, or `nil`.
|
|
393
|
+
def server_banner=(banner)
|
|
394
|
+
raise 'Can only set a banner for the current bot' unless current_bot?
|
|
395
|
+
|
|
396
|
+
update_current_member_data(banner: banner.respond_to?(:read) ? OnyxCord.encode64(banner) : banner)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
# Set the server avatar for the current bot.
|
|
400
|
+
# @param avatar [File, nil] A file like object that responds to read, or `nil`.
|
|
401
|
+
def server_avatar=(avatar)
|
|
402
|
+
raise 'Can only set an avatar for the current bot' unless current_bot?
|
|
403
|
+
|
|
404
|
+
update_current_member_data(avatar: avatar.respond_to?(:read) ? OnyxCord.encode64(avatar) : avatar)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# Set the server bio for the current bot.
|
|
408
|
+
# @param bio [String, nil] The new server bio for the bot, or nil.
|
|
409
|
+
def server_bio=(bio)
|
|
410
|
+
raise 'Can only set a bio for the current bot' unless current_bot?
|
|
411
|
+
|
|
412
|
+
update_current_member_data(bio: bio)
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
# Update this member's roles
|
|
416
|
+
# @note For internal use only.
|
|
417
|
+
# @!visibility private
|
|
418
|
+
def update_roles(role_ids)
|
|
419
|
+
@roles = [server.role(@server_id)]
|
|
420
|
+
role_ids.each do |id|
|
|
421
|
+
# It is possible for members to have roles that do not exist
|
|
422
|
+
# on the server any longer. See https://github.com/onyxcord/onyxcord/issues/371
|
|
423
|
+
role = server.role(id)
|
|
424
|
+
@roles << role if role
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# Update this member's nick
|
|
429
|
+
# @note For internal use only.
|
|
430
|
+
# @!visibility private
|
|
431
|
+
def update_nick(nick)
|
|
432
|
+
@nick = nick
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
# Update this member's boosting timestamp
|
|
436
|
+
# @note For internal user only.
|
|
437
|
+
# @!visibility private
|
|
438
|
+
def update_boosting_since(time)
|
|
439
|
+
@boosting_since = time
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
# @!visibility private
|
|
443
|
+
def update_communication_disabled_until(time)
|
|
444
|
+
time = time ? Time.parse(time) : nil
|
|
445
|
+
@communication_disabled_until = time
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
# Update this member
|
|
449
|
+
# @note For internal use only.
|
|
450
|
+
# @!visibility private
|
|
451
|
+
def update_data(data)
|
|
452
|
+
update_roles(data['roles']) if data['roles']
|
|
453
|
+
@nick = data['nick'] if data.key?('nick')
|
|
454
|
+
@mute = data['mute'] if data.key?('mute')
|
|
455
|
+
@deaf = data['deaf'] if data.key?('deaf')
|
|
456
|
+
@server_avatar_id = data['avatar'] if data.key?('avatar')
|
|
457
|
+
@server_banner_id = data['banner'] if data.key?('banner')
|
|
458
|
+
@flags = data['flags'] if data.key?('flags')
|
|
459
|
+
@pending = data['pending'] if data.key?('pending')
|
|
460
|
+
|
|
461
|
+
@joined_at = Time.parse(data['joined_at']) if data['joined_at']
|
|
462
|
+
|
|
463
|
+
if data.key?('communication_disabled_until')
|
|
464
|
+
timeout_until = data['communication_disabled_until']
|
|
465
|
+
@communication_disabled_until = timeout_until ? Time.parse(timeout_until) : nil
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
if data.key?('premium_since')
|
|
469
|
+
@boosting_since = data['premium_since'] ? Time.parse(data['premium_since']) : nil
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
if (user = data['user'])
|
|
473
|
+
@user.update_global_name(user['global_name']) if user['global_name']
|
|
474
|
+
@user.avatar_id = user['avatar'] if user.key('avatar')
|
|
475
|
+
@user.update_avatar_decoration(user['avatar_decoration_data']) if user.key?('avatar_decoration_data')
|
|
476
|
+
@user.update_collectibles(user['collectibles']) if user.key?('collectibles')
|
|
477
|
+
@user.update_primary_server(user['primary_guild']) if user.key?('primary_guild')
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
@server_collectibles = Collectibles.new(data['collectibles'] || {}, @bot) if data.key?('collectibles')
|
|
481
|
+
@server_avatar_decoration = process_avatar_decoration(data['avatar_decoration_data']) if data.key?('avatar_decoration_data')
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
include PermissionCalculator
|
|
485
|
+
|
|
486
|
+
# Overwriting inspect for debug purposes
|
|
487
|
+
def inspect
|
|
488
|
+
"<Member user=#{@user.inspect} server=#{@server&.inspect || @server_id} joined_at=#{@joined_at} roles=#{@roles&.inspect || @role_ids} voice_channel=#{voice_channel.inspect} mute=#{mute} deaf=#{deaf} self_mute=#{self_mute} self_deaf=#{self_deaf}>"
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
private
|
|
492
|
+
|
|
493
|
+
# Utility method to get a list of role IDs from one role or an array of roles
|
|
494
|
+
def role_id_array(role)
|
|
495
|
+
if role.is_a? Array
|
|
496
|
+
role.map(&:resolve_id)
|
|
497
|
+
else
|
|
498
|
+
[role.resolve_id]
|
|
499
|
+
end
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
# Utility method to get data out of this member's voice state
|
|
503
|
+
def voice_state_attribute(name)
|
|
504
|
+
voice_state = server.voice_states[@user.id]
|
|
505
|
+
voice_state&.send name
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
# @!visibility private
|
|
509
|
+
def resolve_role_ids
|
|
510
|
+
@roles ? @roles.collect(&:id) : @role_ids
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
# @!visibility private
|
|
514
|
+
def update_member_data(new_data)
|
|
515
|
+
update_data(JSON.parse(API::Server.update_member(@bot.token, @server_id, @user.id, **new_data)))
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
# @!visibility private
|
|
519
|
+
def update_current_member_data(new_data)
|
|
520
|
+
update_data(JSON.parse(API::Server.update_current_member(@bot.token, @server_id,
|
|
521
|
+
new_data.key?(:nick) ? new_data[:nick] : :undef,
|
|
522
|
+
new_data[:reason],
|
|
523
|
+
new_data.key?(:bio) ? new_data[:bio] : :undef,
|
|
524
|
+
new_data.key?(:banner) ? new_data[:banner] : :undef,
|
|
525
|
+
new_data.key?(:avatar) ? new_data[:avatar] : :undef)))
|
|
526
|
+
end
|
|
527
|
+
end
|
|
528
|
+
end
|