Skip to content

Commit 05c5caf

Browse files
committed
fix: solve linter issues
1 parent 63cbc70 commit 05c5caf

45 files changed

Lines changed: 588 additions & 450 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/channels/application_cable/connection.rb

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,8 @@ def route_by_token_type(payload)
5252
end
5353

5454
def authenticate_user_connection(payload)
55-
user = User.find_by(id: payload[:user_id])
56-
57-
if user.nil?
58-
logger.warn "[ActionCable] User not found for token user_id=#{payload[:user_id]}"
59-
reject_unauthorized_connection
60-
end
61-
62-
unless user.organization_id.present?
63-
logger.warn "[ActionCable] User #{user.id} has no organization — rejected"
64-
reject_unauthorized_connection
65-
end
55+
user = find_user(payload[:user_id])
56+
validate_organization!(user.organization_id, label: "User #{user.id}")
6657

6758
self.current_user = user
6859
self.current_player = nil
@@ -71,22 +62,36 @@ def authenticate_user_connection(payload)
7162
end
7263

7364
def authenticate_player_connection(payload)
74-
player = Player.unscoped.find_by(id: payload[:player_id], player_access_enabled: true)
75-
76-
if player.nil?
77-
logger.warn "[ActionCable] Player not found or access disabled: player_id=#{payload[:player_id]}"
78-
reject_unauthorized_connection
79-
end
80-
81-
unless player.organization_id.present?
82-
logger.warn "[ActionCable] Player #{player.id} has no organization — rejected"
83-
reject_unauthorized_connection
84-
end
65+
player = find_player(payload[:player_id])
66+
validate_organization!(player.organization_id, label: "Player #{player.id}")
8567

8668
self.current_user = nil
8769
self.current_player = player
8870
self.current_org_id = player.organization_id
8971
logger.info "[ActionCable] Connected: player=#{player.id} org=#{player.organization_id}"
9072
end
73+
74+
def find_user(user_id)
75+
user = User.find_by(id: user_id)
76+
return user if user
77+
78+
logger.warn "[ActionCable] User not found for token user_id=#{user_id}"
79+
reject_unauthorized_connection
80+
end
81+
82+
def find_player(player_id)
83+
player = Player.unscoped.find_by(id: player_id, player_access_enabled: true)
84+
return player if player
85+
86+
logger.warn "[ActionCable] Player not found or access disabled: player_id=#{player_id}"
87+
reject_unauthorized_connection
88+
end
89+
90+
def validate_organization!(org_id, label:)
91+
return if org_id.present?
92+
93+
logger.warn "[ActionCable] #{label} has no organization — rejected"
94+
reject_unauthorized_connection
95+
end
9196
end
9297
end

app/controllers/concerns/authenticatable.rb

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,33 @@ def authenticate_request!
2727

2828
def perform_authentication(token)
2929
@jwt_payload = JwtService.decode(token)
30-
31-
# Reject refresh tokens used as access tokens.
32-
# Refresh tokens carry type: 'refresh' and must never authenticate a request.
3330
raise JwtService::TokenInvalidError, 'Invalid token type' unless valid_access_token_type?(@jwt_payload)
3431

35-
if @jwt_payload[:entity_type] == 'player'
36-
authenticate_player_token
37-
else
38-
authenticate_user_token
39-
end
32+
dispatch_token_authentication
4033
rescue JwtService::AuthenticationError => e
4134
Rails.logger.error("JWT Authentication error: #{e.class} - #{e.message}")
4235
render_unauthorized(e.message)
4336
rescue ActiveRecord::RecordNotFound => e
4437
Rails.logger.error("User not found during authentication: #{e.message}")
4538
render_unauthorized('User not found')
4639
rescue StandardError => e
47-
Rails.logger.error("Unexpected authentication error: #{e.class} - #{e.message}")
48-
Rails.logger.error(e.backtrace.join("\n"))
40+
handle_unexpected_auth_error(e)
41+
end
42+
43+
def dispatch_token_authentication
44+
# Reject refresh tokens used as access tokens.
45+
# Refresh tokens carry type: 'refresh' and must never authenticate a request.
46+
# Player access tokens carry entity_type: 'player' AND type: 'access'.
47+
if @jwt_payload[:entity_type] == 'player'
48+
authenticate_player_token
49+
else
50+
authenticate_user_token
51+
end
52+
end
53+
54+
def handle_unexpected_auth_error(error)
55+
Rails.logger.error("Unexpected authentication error: #{error.class} - #{error.message}")
56+
Rails.logger.error(error.backtrace.join("\n"))
4957
render json: { error: { code: 'INTERNAL_ERROR', message: 'An internal error occurred' } },
5058
status: :internal_server_error
5159
end

app/controllers/internal/organizations_controller.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# frozen_string_literal: true
22

33
module Internal
4+
# Internal API controller for updating organization tier and subscription data.
5+
# Called exclusively by the ProPay payment gateway via a signed internal JWT.
46
class OrganizationsController < ActionController::API
57
include InternalServiceAuthenticatable
68

app/controllers/status_controller.rb

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ class StatusController < ActionController::API
66
skip_before_action :verify_authenticity_token, raise: false
77

88
COMPONENT_META = {
9-
'api' => { name: 'API', description: 'Core REST API services' },
10-
'database' => { name: 'Database', description: 'PostgreSQL primary database' },
11-
'redis' => { name: 'Cache & Background Jobs', description: 'Redis cache and Sidekiq queue processor' },
12-
'websocket' => { name: 'Real-time (WebSocket)', description: 'ActionCable WebSocket connections' },
13-
'sidekiq' => { name: 'Background Jobs (Sidekiq)', description: 'Async job processing' },
14-
'riot_api' => { name: 'Riot API Integration', description: 'Riot Games data synchronization' }
9+
'api' => { name: 'API', description: 'Core REST API services' },
10+
'database' => { name: 'Database', description: 'PostgreSQL primary database' },
11+
'redis' => { name: 'Cache & Background Jobs', description: 'Redis cache and Sidekiq queue processor' },
12+
'websocket' => { name: 'Real-time (WebSocket)', description: 'ActionCable WebSocket connections' },
13+
'sidekiq' => { name: 'Background Jobs (Sidekiq)', description: 'Async job processing' },
14+
'riot_api' => { name: 'Riot API Integration', description: 'Riot Games data synchronization' }
1515
}.freeze
1616

1717
def index
@@ -22,19 +22,19 @@ def index
2222
indicator, description = overall_status(components)
2323

2424
{
25-
status: { indicator: indicator, description: description },
26-
components: components,
27-
incidents: incidents,
25+
status: { indicator: indicator, description: description },
26+
components: components,
27+
incidents: incidents,
2828
uptime_history: uptime
2929
}
3030
end
3131

3232
render json: cached.merge(
3333
page: {
34-
id: 'prostaff',
35-
name: 'ProStaff',
36-
url: 'https://status.prostaff.gg',
37-
time_zone: 'UTC',
34+
id: 'prostaff',
35+
name: 'ProStaff',
36+
url: 'https://status.prostaff.gg',
37+
time_zone: 'UTC',
3838
updated_at: Time.current.iso8601
3939
}
4040
), status: :ok
@@ -57,13 +57,13 @@ def build_component_statuses
5757
def build_component_from_snapshot(component, snapshot)
5858
meta = COMPONENT_META[component]
5959
{
60-
id: component,
61-
name: meta[:name],
62-
status: snapshot.status,
63-
description: meta[:description],
60+
id: component,
61+
name: meta[:name],
62+
status: snapshot.status,
63+
description: meta[:description],
6464
response_time_ms: snapshot.response_time_ms,
65-
last_checked_at: snapshot.checked_at.iso8601,
66-
updated_at: snapshot.updated_at.iso8601
65+
last_checked_at: snapshot.checked_at.iso8601,
66+
updated_at: snapshot.updated_at.iso8601
6767
}
6868
end
6969

@@ -72,13 +72,13 @@ def build_component_live(component)
7272
result = live_check(component)
7373

7474
{
75-
id: component,
76-
name: meta[:name],
77-
status: result[:status],
78-
description: meta[:description],
75+
id: component,
76+
name: meta[:name],
77+
status: result[:status],
78+
description: meta[:description],
7979
response_time_ms: result[:response_time_ms],
80-
last_checked_at: Time.current.iso8601,
81-
updated_at: Time.current.iso8601
80+
last_checked_at: Time.current.iso8601,
81+
updated_at: Time.current.iso8601
8282
}
8383
end
8484

@@ -122,16 +122,16 @@ def build_incidents
122122

123123
def serialize_incident(incident)
124124
{
125-
id: incident.id,
126-
title: incident.title,
127-
body: incident.body,
128-
severity: incident.severity,
129-
status: incident.status,
125+
id: incident.id,
126+
title: incident.title,
127+
body: incident.body,
128+
severity: incident.severity,
129+
status: incident.status,
130130
affected_components: incident.affected_components,
131-
started_at: incident.started_at.iso8601,
132-
resolved_at: incident.resolved_at&.iso8601,
133-
postmortem: incident.postmortem,
134-
updates: incident.updates.order(created_at: :desc).map do |u|
131+
started_at: incident.started_at.iso8601,
132+
resolved_at: incident.resolved_at&.iso8601,
133+
postmortem: incident.postmortem,
134+
updates: incident.updates.order(created_at: :desc).map do |u|
135135
{ id: u.id, status: u.status, body: u.body, created_at: u.created_at.iso8601 }
136136
end
137137
}

app/jobs/ml_health_check_job.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def check_service_health
4242
end
4343

4444
if body['model_loaded'] == false
45-
Rails.logger.warn("[MlHealthCheckJob] ML service health: model_loaded=false")
45+
Rails.logger.warn('[MlHealthCheckJob] ML service health: model_loaded=false')
4646
else
4747
Rails.logger.info("[MlHealthCheckJob] ML service healthy (model_loaded=#{body['model_loaded']})")
4848
end

app/jobs/rolling_auc_job.rb

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ def perform
3737
auc = calculate_auc_roc(y_true, y_score)
3838
mean_prob = y_score.sum / y_score.size
3939

40-
persist_metrics(auc: auc.round(4), n: logs.size, mean_prob: mean_prob.round(4))
41-
emit_alerts(auc: auc, mean_prob: mean_prob, n: logs.size)
40+
persist_metrics(auc: auc.round(4), sample_size: logs.size, mean_prob: mean_prob.round(4))
41+
emit_alerts(auc: auc, mean_prob: mean_prob, sample_size: logs.size)
4242

4343
record_job_heartbeat
4444
rescue StandardError => e
@@ -65,16 +65,19 @@ def calculate_auc_roc(y_true, y_score)
6565

6666
sorted = y_true.zip(y_score).sort_by { |_, score| -score }
6767

68-
tp = 0; fp = 0; prev_fp = 0; auc = 0.0
68+
tp = 0
69+
fp = 0
70+
prev_fp = 0
71+
auc = 0.0
6972

70-
sorted.each do |label, _|
73+
sorted.each_key do |label|
7174
if label == 1
7275
tp += 1
7376
else
7477
# Accumulate trapezoid area for the strip [prev_fp..fp]
7578
auc += tp.to_f * (fp - prev_fp + 1) / (n_pos * n_neg)
7679
prev_fp = fp
77-
fp += 1
80+
fp += 1
7881
end
7982
end
8083

@@ -84,21 +87,19 @@ def calculate_auc_roc(y_true, y_score)
8487
[auc, 1.0].min
8588
end
8689

87-
def persist_metrics(auc:, n:, mean_prob:)
90+
def persist_metrics(auc:, sample_size:, mean_prob:)
8891
Sidekiq.redis { |r| r.call('SET', 'ml:metrics:rolling_auc', auc.to_s) }
89-
Sidekiq.redis { |r| r.call('SET', 'ml:metrics:n_predictions', n.to_s) }
92+
Sidekiq.redis { |r| r.call('SET', 'ml:metrics:n_predictions', sample_size.to_s) }
9093
Sidekiq.redis { |r| r.call('SET', 'ml:metrics:mean_win_prob', mean_prob.to_s) }
9194
rescue StandardError => e
9295
Rails.logger.warn("[RollingAucJob] Failed to persist metrics to Redis: #{e.message}")
9396
end
9497

95-
def emit_alerts(auc:, mean_prob:, n:)
96-
if auc < 0.51
97-
Rails.logger.warn("[RollingAucJob] ML rolling AUC degraded: #{auc} (n=#{n})")
98-
end
98+
def emit_alerts(auc:, mean_prob:, sample_size:)
99+
Rails.logger.warn("[RollingAucJob] ML rolling AUC degraded: #{auc} (n=#{sample_size})") if auc < 0.51
99100

100-
if mean_prob < 0.48 || mean_prob > 0.58
101-
Rails.logger.warn("[RollingAucJob] ML win prob drift: mean=#{mean_prob} (n=#{n})")
102-
end
101+
return unless mean_prob < 0.48 || mean_prob > 0.58
102+
103+
Rails.logger.warn("[RollingAucJob] ML win prob drift: mean=#{mean_prob} (n=#{sample_size})")
103104
end
104105
end

app/models/status_snapshot.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@ class StatusSnapshot < ApplicationRecord
1616

1717
# Returns daily uptime percentage for a component over the last N days.
1818
def self.uptime_by_day(component:, days: 90)
19-
rows = for_component(component).recent(days).order(checked_at: :asc).pluck(:checked_at, :status)
19+
rows = for_component(component).recent(days).order(checked_at: :asc).pluck(:checked_at, :status)
2020
rows.group_by { |checked_at, _| checked_at.to_date }
2121
.map { |date, entries| aggregate_day(date, entries) }
2222
end
2323

2424
# Single-query bulk version: returns { component => [{ date:, uptime_pct:, status: }] }
2525
def self.bulk_uptime_by_day(days: 90)
2626
rows = where(checked_at: days.days.ago..Time.current)
27-
.order(checked_at: :asc)
28-
.pluck(:component, :checked_at, :status)
27+
.order(checked_at: :asc)
28+
.pluck(:component, :checked_at, :status)
2929

3030
rows
3131
.group_by(&:first)

app/modules/admin/controllers/ml_metrics_controller.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ def index
2828
rescue StandardError => e
2929
Rails.logger.warn("[Admin::MlMetricsController] Failed to read metrics: #{e.message}")
3030
render_success({
31-
rolling_auc: nil,
31+
rolling_auc: nil,
3232
mean_win_prob: nil,
3333
n_predictions: nil,
34-
circuit_open: false
34+
circuit_open: false
3535
})
3636
end
3737

@@ -55,10 +55,10 @@ def read_metrics_from_redis
5555
open_until = r.call('GET', MlServiceClient::CIRCUIT_OPEN_UNTIL_KEY).to_i
5656

5757
{
58-
rolling_auc: auc_raw ? auc_raw.to_f : nil,
59-
mean_win_prob: mean_raw ? mean_raw.to_f : nil,
60-
n_predictions: n_raw ? n_raw.to_i : nil,
61-
circuit_open: open_until > Time.now.to_i
58+
rolling_auc: auc_raw&.to_f,
59+
mean_win_prob: mean_raw&.to_f,
60+
n_predictions: n_raw&.to_i,
61+
circuit_open: open_until > Time.now.to_i
6262
}
6363
end
6464
end

0 commit comments

Comments
 (0)