Skip to content

Commit

Permalink
More sigs
Browse files Browse the repository at this point in the history
  • Loading branch information
Arie committed Aug 17, 2024
1 parent 71907a3 commit d3a0529
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 17 deletions.
14 changes: 12 additions & 2 deletions app/models/order.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# typed: false
# typed: true
# frozen_string_literal: true

class Order < ActiveRecord::Base
extend T::Sig

self.table_name = :paypal_orders
belongs_to :product
belongs_to :user
Expand All @@ -13,6 +15,7 @@ class Order < ActiveRecord::Base

validates_presence_of :user_id, :product_id

sig { returns(T.nilable(String)) }
def handle_successful_payment!
update(status: 'Completed')
if gift?
Expand All @@ -23,35 +26,42 @@ def handle_successful_payment!
announce_donator
end

sig { returns(T.nilable(String)) }
def announce_donator
AnnounceDonatorWorker.perform_async(user.nickname, product_name)
AnnounceDonatorWorker.perform_async(user&.nickname, product_name)
end

sig { params(now: ActiveSupport::TimeWithZone).returns(T.any(Integer, Float, BigDecimal)) }
def self.monthly_total(now = Time.current)
completed.monthly(now).joins(:product).sum('products.price')
end

sig { returns(T.any(ActiveRecord::Relation, ActiveRecord::Associations::CollectionProxy, T.untyped)) }
def self.completed
where(status: 'Completed')
end

sig { params(now: ActiveSupport::TimeWithZone).returns(T.any(Float, BigDecimal)) }
def self.monthly_goal_percentage(now = Time.current)
(monthly_total(now) / monthly_goal) * 100.0
end

sig { params(now: ActiveSupport::TimeWithZone).returns(T.any(ActiveRecord::Relation, ActiveRecord::Associations::CollectionProxy)) }
def self.monthly(now = Time.current)
beginning_of_month = now.beginning_of_month
end_of_month = now.end_of_month
where(arel_table[:created_at].gt(beginning_of_month))
.where(arel_table[:created_at].lt(end_of_month))
end

sig { returns(T::Array[T::Array[T.any(BigDecimal, User)]]) }
def self.leaderboard
completed.group(:user).joins(:user).joins(:product).sum('products.price').sort_by do |_user, amount|
amount
end.reverse
end

sig { params(site_host: String).returns(Float) }
def self.monthly_goal(site_host = SITE_HOST)
case site_host
when 'serveme.tf'
Expand Down
6 changes: 6 additions & 0 deletions app/models/product.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@
# frozen_string_literal: true

class Product < ActiveRecord::Base
extend T::Sig

has_many :orders
validates_presence_of :name, :price

sig { returns(String) }
def list_name
"#{name} - #{price.round.to_i} #{currency}"
end

sig { returns(Integer) }
def price_in_cents
price.round * 100
end

sig { returns(T.any(ActiveRecord::Relation, ActiveRecord::Associations::CollectionProxy)) }
def self.active
where(active: true)
end

sig { returns(T.any(ActiveRecord::Relation, ActiveRecord::Associations::CollectionProxy)) }
def self.ordered
order(:price)
end
Expand Down
23 changes: 21 additions & 2 deletions app/models/reservation_player.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# frozen_string_literal: true

class ReservationPlayer < ActiveRecord::Base
extend T::Sig

require 'csv'
require 'ipaddr'
belongs_to :reservation, optional: true
Expand All @@ -11,60 +13,74 @@ class ReservationPlayer < ActiveRecord::Base
geocoded_by :ip
before_save :geocode, if: :ip_changed?

sig { returns(T.any(ActiveRecord::Relation, ActiveRecord::Associations::CollectionProxy)) }
def duplicates
self.class.where(reservation_id: reservation_id).where(steam_uid: steam_uid).where(ip: ip)
end

sig { returns(T.any(ActiveRecord::Relation, ActiveRecord::Associations::CollectionProxy)) }
def self.whitelisted
where(whitelisted: true)
end

sig { params(steam_profile: SteamCondenser::Community::SteamId).returns(T.nilable(T.any(T::Boolean, String))) }
def self.banned?(steam_profile)
(banned_name?(steam_profile&.nickname) || banned_uid?(steam_profile&.steam_id64)) && !whitelisted_uid?(steam_profile&.steam_id64)
(banned_name?(steam_profile.nickname) || banned_uid?(steam_profile.steam_id64)) && !whitelisted_uid?(steam_profile.steam_id64)
end

sig { params(nickname: String).returns(T::Boolean) }
def self.banned_name?(nickname)
nickname.include?('﷽')
end

sig { params(steam_id64: T.nilable(T.any(Integer, String))).returns(T.nilable(T.any(String, T::Boolean))) }
def self.whitelisted_uid?(steam_id64)
return true unless steam_id64

whitelisted_uids[steam_id64.to_i]
end

sig { returns(T::Hash[Integer, String]) }
def self.whitelisted_uids
@whitelisted_uids ||= CSV.read(Rails.root.join('doc', 'whitelisted_steam_ids.csv'), headers: true).to_h { |row| [row['steam_id64'].to_i, row['reason']] }
end

sig { params(steam_id64: T.nilable(T.any(Integer, String))).returns(T.nilable(String)) }
def self.banned_uid?(steam_id64)
banned_uids[steam_id64.to_i]
end

sig { params(ip: T.nilable(String)).returns(T::Boolean) }
def self.banned_ip?(ip)
banned_ranges.any? { |range| range.include?(ip) }
end

sig { params(steam_id64: T.any(Integer, String)).returns(T.nilable(T::Boolean)) }
def self.banned_league_uid?(steam_id64)
LeagueBan.fetch(steam_id64)&.banned?
end

sig { returns(T::Hash[Integer, String]) }
def self.banned_uids
@banned_uids ||= CSV.read(Rails.root.join('doc', 'banned_steam_ids.csv'), headers: true).to_h { |row| [row['steam_id64'].to_i, row['reason']] }
end

sig { returns(T::Array[String]) }
def self.banned_ranges
@banned_ranges ||= CSV.read(Rails.root.join('doc', 'banned_ips.csv'), headers: true).map { |row| IPAddr.new(row['ip']) }
end

sig { params(ip: T.nilable(String)).returns(T::Boolean) }
def self.banned_asn_ip?(ip)
banned_asn?(asn(ip))
end

sig { params(asn: T.nilable(MaxMind::GeoIP2::Model::ASN)).returns(T::Boolean) }
def self.banned_asn?(asn)
!!asn && (banned_asns.include?(asn&.autonomous_system_number) || custom_banned_asns.include?(asn&.autonomous_system_number))
!!asn && (banned_asns.include?(asn.autonomous_system_number) || custom_banned_asns.include?(asn.autonomous_system_number))
end

sig { params(ip: T.nilable(String)).returns(T.nilable(MaxMind::GeoIP2::Model::ASN)) }
def self.asn(ip)
return nil if IPAddr.new('169.254.0.0/16').include?(ip)

Expand All @@ -75,10 +91,12 @@ def self.asn(ip)
end
end

sig { returns(T::Array[Integer]) }
def self.banned_asns
@banned_asns ||= CSV.read(Rails.root.join('doc', 'bad-asn-list.csv'), headers: true).map { |row| row['ASN'].to_i }
end

sig { returns(T::Array[Integer]) }
def self.custom_banned_asns
[
3214, # xTom
Expand All @@ -92,6 +110,7 @@ def self.custom_banned_asns
]
end

sig { params(ip: String).returns(T::Boolean) }
def self.banned_country?(ip)
geocode_result = Geocoder.search(ip).first
return false unless geocode_result
Expand Down
15 changes: 13 additions & 2 deletions app/models/statistic.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# typed: false
# typed: true
# frozen_string_literal: true

class Statistic
extend T::Sig

sig { returns(Hash) }
def self.top_10_users
top_10_user_id_count_hash = Reservation.joins(:user).order(Arel.sql('count_all DESC')).limit(10).group('users.id').count
top_10_users = User.where(id: top_10_user_id_count_hash.keys).includes(:groups).to_a
Expand All @@ -13,26 +16,32 @@ def self.top_10_users
top_10_hash
end

sig { returns(Hash) }
def self.top_10_servers
Reservation.joins(:server).order(Arel.sql('count_all DESC')).limit(10).group('servers.name').count
end

sig { returns(Integer) }
def self.total_reservations
Reservation.count
end

sig { returns(T.any(Integer, Float, BigDecimal)) }
def self.total_playtime_seconds
Reservation.sum(:duration)
end

sig { returns(GoogleVisualr::Interactive::ColumnChart) }
def self.reservations_per_day_chart
reservations_per_time_unit('Date', reservations_per_day, 'Reservations in the last 50 days')
end

sig { returns(GoogleVisualr::Interactive::ColumnChart) }
def self.reserved_hours_per_month_chart
reservations_per_time_unit('Month', reserved_hours_per_month, 'Hours played', 'Hours played')
end

sig { params(time_unit: String, statistics_array: Array, title: String, bar_title: String).returns(GoogleVisualr::Interactive::ColumnChart) }
def self.reservations_per_time_unit(time_unit, statistics_array, title, bar_title = 'Reservation')
data_table = GoogleVisualr::DataTable.new
data_table.new_column('string', time_unit)
Expand All @@ -42,14 +51,16 @@ def self.reservations_per_time_unit(time_unit, statistics_array, title, bar_titl
GoogleVisualr::Interactive::ColumnChart.new(data_table, option)
end

sig { returns(T::Array[Array]) }
def self.reservations_per_day
Rails.cache.fetch "reservations_per_day_#{Date.current}", expires_in: 1.hour do
Reservation.order(Arel.sql('DATE(starts_at) DESC')).group(Arel.sql('DATE(starts_at)')).limit(50).count(:id).collect do |date, count|
Reservation.order(Arel.sql('DATE(starts_at) DESC')).limit(50).group(Arel.sql('DATE(starts_at)')).count(:id).collect do |date, count|
[date.to_s, count]
end.reverse
end
end

sig { returns(T::Array[Array]) }
def self.reserved_hours_per_month
Rails.cache.fetch "reserved_hours_per_month_#{Date.current}", expires_in: 1.hour do
result = ActiveRecord::Base.connection.execute("SELECT TO_CHAR(starts_at, 'YYYY-MM') AS year_month,
Expand Down
11 changes: 7 additions & 4 deletions app/models/stripe_order.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
# typed: false
# typed: true
# frozen_string_literal: true

class StripeOrder < Order
extend T::Sig

sig { returns(String) }
def charge
stripe_charge = Stripe::Charge.create(
capture: true,
amount: product.price_in_cents,
currency: product.currency,
amount: product&.price_in_cents,
currency: product&.currency,
description: "#{SITE_URL} - #{product_name}",
source: payer_id,
metadata: {
site_url: SITE_URL,
order_id: id,
steam_uid: user.uid,
steam_uid: user&.uid,
product_name: product_name
}
)
Expand Down
4 changes: 2 additions & 2 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# typed: false
# typed: true
# frozen_string_literal: true

class User < ActiveRecord::Base
Expand Down Expand Up @@ -99,7 +99,7 @@ def top10?

sig { returns(T.nilable(ActiveSupport::TimeWithZone)) }
def donator_until
group_users.find_by_group_id(Group.donator_group)&.expires_at
group_users.find_by(group_id: Group.donator_group)&.expires_at
end

sig { returns(T::Boolean) }
Expand Down
9 changes: 9 additions & 0 deletions app/models/voucher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,29 @@
# frozen_string_literal: true

class Voucher < ActiveRecord::Base
extend T::Sig

belongs_to :product, optional: true
belongs_to :order, optional: true
belongs_to :claimed_by, class_name: 'User', optional: true
belongs_to :created_by, class_name: 'User', optional: true

sig { returns(String) }
def hyphenate
Base32::Crockford.hypenate(code).upcase
end

sig { params(product: Product).returns(Voucher) }
def self.generate!(product)
create!(product: product, code: generate_code)
end

sig { returns(String) }
def self.generate_code
encode(SecureRandom.hex(8).to_i(16))
end

sig { params(code: Integer).returns(String) }
def self.encode(code)
Base32::Crockford.encode(code).upcase
end
Expand All @@ -27,13 +33,15 @@ def self.unclaimed
where(claimed_at: nil)
end

sig { params(code: String).returns(T.nilable(Voucher)) }
def self.find_voucher(code)
code = encode(Base32::Crockford.decode(code, :integer))
where(code: code).first
rescue StandardError
nil
end

sig { params(user: User).returns(T::Boolean) }
def claim!(user)
with_lock do
reload
Expand All @@ -46,6 +54,7 @@ def claim!(user)
end
end

sig { returns(T::Boolean) }
def claimed?
claimed_at?
end
Expand Down
4 changes: 4 additions & 0 deletions app/models/whitelist.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@
# frozen_string_literal: true

class Whitelist < ActiveRecord::Base
extend T::Sig

has_many :reservations, dependent: :nullify

validates_presence_of :file

sig { returns(T.any(ActiveRecord::Relation, ActiveRecord::Associations::CollectionProxy)) }
def self.active
where(hidden: false)
end

sig { returns(T.any(ActiveRecord::Relation, ActiveRecord::Associations::CollectionProxy)) }
def self.ordered
order('lower(file)')
end
Expand Down
Loading

0 comments on commit d3a0529

Please sign in to comment.