# frozen_string_literal: true
module ESM
class Cooldown < ApplicationRecord
# =============================================================================
# INITIALIZE
# =============================================================================
TYPES = %w[times seconds minutes hours days].freeze
# =============================================================================
# DATA STRUCTURE
# =============================================================================
attribute :community_id, :integer
attribute :server_id, :integer
attribute :user_id, :integer
attribute :steam_uid, :string
attribute :command_name, :string
attribute :cooldown_quantity, :integer, default: 1
attribute :cooldown_type, :string, default: "seconds"
attribute :cooldown_amount, :integer, default: 0
attribute :expires_at, :datetime, default: -> { 1.second.ago }
attribute :created_at, :datetime
attribute :updated_at, :datetime
# =============================================================================
# ASSOCIATIONS
# =============================================================================
belongs_to :user
belongs_to :server
belongs_to :community
# =============================================================================
# VALIDATIONS
# =============================================================================
# =============================================================================
# CALLBACKS
# =============================================================================
after_find :adjust_for_community_changes
# =============================================================================
# SCOPES
# =============================================================================
# =============================================================================
# CLASS METHODS
# =============================================================================
# =============================================================================
# INSTANCE METHODS
# =============================================================================
def user
return ESM::User.where(id: user_id).first if user_id.present?
return ESM::User.find_by_steam_uid(steam_uid) if steam_uid.present?
nil
end
def active?
if cooldown_type == "times"
cooldown_amount >= cooldown_quantity
else
expires_at >= ::Time.current
end
end
def to_s
ESM::Time.distance_of_time_in_words(expires_at)
end
def reset!
update!(expires_at: 5.seconds.ago, cooldown_amount: 0)
end
def update_expiry!(executed_at, cooldown_time)
case cooldown_time
# 1.times, 5.times...
when Enumerator, Integer
update!(
cooldown_quantity: cooldown_time.is_a?(Integer) ? cooldown_time : cooldown_time.size,
cooldown_type: "times",
cooldown_amount: cooldown_amount + 1
)
# 1.second, 5.days
when ActiveSupport::Duration
# Converts 1.second to [:seconds, 1]
type, quantity = cooldown_time.parts.to_a.first
update!(cooldown_quantity: quantity, cooldown_type: type, expires_at: (executed_at + cooldown_time).to_time)
end
end
private
# If the community changes the configuration for a command, this will adjust the cooldown to match.
# Mainly used to adjust a cooldown if it was changed to a lesser time, such as 24 hours to 2 seconds.
# The user shouldn't have to wait 24 hours when the new cooldown is 2 seconds
def adjust_for_community_changes
# Commands that have no community_id and are used in DMs will not be able to use this code
return if community.nil?
configuration = community.command_configurations.where(command_name: command_name).first
return if configuration.nil?
return if configuration.cooldown_type == cooldown_type && configuration.cooldown_quantity == cooldown_quantity
# They have changed to times, just reset the cooldown_amount to 0
# Or they have changed from times to seconds (minutes, hours, etc.)
if configuration.cooldown_type == "times" || (configuration.cooldown_type != "times" && cooldown_type == "times")
self.expires_at = 1.second.ago
self.cooldown_amount = 0
else
# Converts 1, "minutes" to 1.minutes to 60 (seconds)
new_cooldown_seconds = configuration.cooldown_quantity.send(configuration.cooldown_type).to_i
current_cooldown_seconds = cooldown_quantity.send(cooldown_type).to_i
# Adjust the expiry time to compensate if the new time is less than the current
self.expires_at = expires_at - (current_cooldown_seconds - new_cooldown_seconds) if new_cooldown_seconds < current_cooldown_seconds
end
self.cooldown_type = configuration.cooldown_type
self.cooldown_quantity = configuration.cooldown_quantity
save!
end
end
end