diff --git a/lib/discordrb/api/server.rb b/lib/discordrb/api/server.rb index 1800166ce..6751fa303 100644 --- a/lib/discordrb/api/server.rb +++ b/lib/discordrb/api/server.rb @@ -140,7 +140,8 @@ def resolve_members(token, server_id, limit, after = nil) # Update a user properties # https://discord.com/developers/docs/resources/guild#modify-guild-member - def update_member(token, server_id, user_id, nick: nil, roles: nil, mute: nil, deaf: nil, channel_id: nil, reason: nil) + def update_member(token, server_id, user_id, nick: :undef, roles: :undef, mute: :undef, deaf: :undef, channel_id: :undef, + communication_disabled_until: :undef, reason: nil) Discordrb::API.request( :guilds_sid_members_uid, server_id, @@ -150,8 +151,9 @@ def update_member(token, server_id, user_id, nick: nil, roles: nil, mute: nil, d nick: nick, mute: mute, deaf: deaf, - channel_id: channel_id - }.compact.to_json, + channel_id: channel_id, + communication_disabled_until: communication_disabled_until + }.reject { |_, v| v == :undef }.to_json, Authorization: token, content_type: :json, 'X-Audit-Log-Reason': reason diff --git a/lib/discordrb/bot.rb b/lib/discordrb/bot.rb index 62b349d27..dfc09f317 100644 --- a/lib/discordrb/bot.rb +++ b/lib/discordrb/bot.rb @@ -1047,6 +1047,7 @@ def update_guild_member(data) member.update_roles(data['roles']) member.update_nick(data['nick']) member.update_boosting_since(data['premium_since']) + member.update_communication_disabled_until(data['communication_disabled_until']) end # Internal handler for GUILD_MEMBER_DELETE diff --git a/lib/discordrb/commands/container.rb b/lib/discordrb/commands/container.rb index 0c2b06926..069e6819f 100644 --- a/lib/discordrb/commands/container.rb +++ b/lib/discordrb/commands/container.rb @@ -86,7 +86,7 @@ def remove_command(name) # Adds all commands from another container into this one. Existing commands will be overwritten. # @param container [Module] A module that `extend`s {CommandContainer} from which the commands will be added. def include_commands(container) - handlers = container.instance_variable_get '@commands' + handlers = container.instance_variable_get :@commands return unless handlers @commands ||= {} diff --git a/lib/discordrb/commands/rate_limiter.rb b/lib/discordrb/commands/rate_limiter.rb index ffdd83c72..c208a2b6a 100644 --- a/lib/discordrb/commands/rate_limiter.rb +++ b/lib/discordrb/commands/rate_limiter.rb @@ -125,7 +125,7 @@ def clean # Adds all the buckets from another RateLimiter onto this one. # @param limiter [Module] Another {RateLimiter} module def include_buckets(limiter) - buckets = limiter.instance_variable_get('@buckets') || {} + buckets = limiter.instance_variable_get(:@buckets) || {} @buckets ||= {} @buckets.merge! buckets end diff --git a/lib/discordrb/container.rb b/lib/discordrb/container.rb index ed6c530d7..cdd747d16 100644 --- a/lib/discordrb/container.rb +++ b/lib/discordrb/container.rb @@ -632,7 +632,7 @@ def add_handler(handler) # @param container [Module] A module that `extend`s {EventContainer} from which the handlers will be added. def include_events(container) application_command_handlers = container.instance_variable_get(:@application_commands) - handlers = container.instance_variable_get '@event_handlers' + handlers = container.instance_variable_get :@event_handlers return unless handlers || application_command_handlers @event_handlers ||= {} diff --git a/lib/discordrb/data/member.rb b/lib/discordrb/data/member.rb index 99c2ab111..81f479bfb 100644 --- a/lib/discordrb/data/member.rb +++ b/lib/discordrb/data/member.rb @@ -18,6 +18,10 @@ module MemberAttributes # @return [Server] the server this member is on. attr_reader :server + + # @return [Time] When the user's timeout will expire. + attr_reader :communication_disabled_until + alias_method :timeout, :communication_disabled_until end # A member is a user on a server. It differs from regular users in that it has roles, voice statuses and things like @@ -70,6 +74,8 @@ def initialize(data, server, bot) @nick = data['nick'] @joined_at = data['joined_at'] ? Time.parse(data['joined_at']) : nil @boosting_since = data['premium_since'] ? Time.parse(data['premium_since']) : nil + timeout_until = data['communication_disabled_until'] + @communication_disabled_until = timeout_until ? Time.parse(timeout_until) : nil end # @return [Server] the server this member is on. @@ -116,6 +122,24 @@ def roles=(role) set_roles(role) end + # Check if the current user has communication disabled. + # @return [true, false] + def communication_disabled? + !@communication_disabled_until.nil? && @communication_disabled_until > Time.now + end + + alias_method :timeout?, :communication_disabled? + + # Set a user's timeout duration, or remove it by setting the timeout to `nil`. + # @param timeout_until [Time, nil] When the timeout will end. + def communication_disabled_until=(timeout_until) + raise ArgumentError, 'A time out cannot exceed 28 days' if timeout_until && timeout_until > (Time.now + 2_419_200) + + API::Server.update_member(@bot.token, @server_id, @user.id, communication_disabled_until: timeout_until.iso8601) + end + + alias_method :timeout=, :communication_disabled_until= + # Bulk sets a member's roles. # @param role [Role, Array] The role(s) to set. # @param reason [String] The reason the user's roles are being changed. @@ -296,6 +320,12 @@ def update_boosting_since(time) @boosting_since = time end + # @!visibility private + def update_communication_disabled_until(time) + time = time ? Time.parse(time) : nil + @communication_disabled_until = time + end + # Update this member # @note For internal use only. # @!visibility private @@ -306,6 +336,8 @@ def update_data(data) @deaf = data['deaf'] if data.key?('deaf') @joined_at = Time.parse(data['joined_at']) if data['joined_at'] + timeout_until = data['communication_disabled_until'] + @communication_disabled_until = timeout_until ? Time.parse(timeout_until) : nil end include PermissionCalculator diff --git a/lib/discordrb/errors.rb b/lib/discordrb/errors.rb index 61402c9df..8710d8e44 100644 --- a/lib/discordrb/errors.rb +++ b/lib/discordrb/errors.rb @@ -87,7 +87,7 @@ def flatten_errors(err, prev_key = nil) # rubocop:disable Naming/MethodName def self.Code(code) classy = Class.new(CodeError) - classy.instance_variable_set('@code', code) + classy.instance_variable_set(:@code, code) @code_classes ||= {} @code_classes[code] = classy diff --git a/spec/permissions_spec.rb b/spec/permissions_spec.rb index 8ef360ad8..ac0767d7f 100644 --- a/spec/permissions_spec.rb +++ b/spec/permissions_spec.rb @@ -31,8 +31,8 @@ it 'sets an attribute for each flag' do expect( [ - subject.instance_variable_get('@foo'), - subject.instance_variable_get('@bar') + subject.instance_variable_get(:@foo), + subject.instance_variable_get(:@bar) ] ).to eq [false, false] end