Refactor TelegramBotLog status handling and add helper
- Remove no_results status enum value, treat zero results as successful searches - Add processing status for initial log creation - Create TelegramBotLogsHelper#status_color_class to eliminate view duplication - Refactor TelegramBotTask to use Stopwatch class for timing measurements - Add total_request_time column to track end-to-end request duration - Update factories, tests, and views to support new status model - Add comprehensive helper tests and maintain full test coverage
This commit is contained in:
21
app/helpers/telegram_bot_logs_helper.rb
Normal file
21
app/helpers/telegram_bot_logs_helper.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
# typed: strict
|
||||
|
||||
module TelegramBotLogsHelper
|
||||
extend T::Sig
|
||||
|
||||
sig { params(telegram_bot_log: TelegramBotLog).returns(String) }
|
||||
def status_color_class(telegram_bot_log)
|
||||
case telegram_bot_log.status
|
||||
when "processing"
|
||||
"bg-blue-100 text-blue-800"
|
||||
when "success"
|
||||
"bg-green-100 text-green-800"
|
||||
when "error"
|
||||
"bg-red-100 text-red-800"
|
||||
when "invalid_image"
|
||||
"bg-orange-100 text-orange-800"
|
||||
else
|
||||
"bg-slate-100 text-slate-800"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,19 +3,19 @@
|
||||
class Stopwatch
|
||||
extend T::Sig
|
||||
|
||||
sig { params(start_time: T.any(Time, ActiveSupport::TimeWithZone)).void }
|
||||
sig { params(start_time: Time).void }
|
||||
def initialize(start_time)
|
||||
@start_time = T.let(start_time, T.any(Time, ActiveSupport::TimeWithZone))
|
||||
@start_time = T.let(start_time, Time)
|
||||
end
|
||||
|
||||
sig { returns(Stopwatch) }
|
||||
def self.start
|
||||
new(Time.current)
|
||||
new(Time.now)
|
||||
end
|
||||
|
||||
sig { returns(Float) }
|
||||
def elapsed
|
||||
Time.current - @start_time
|
||||
Time.now - @start_time
|
||||
end
|
||||
|
||||
sig { returns(String) }
|
||||
@@ -28,7 +28,7 @@ class Stopwatch
|
||||
"#{sprintf("%.3f", elapsed)}s"
|
||||
end
|
||||
|
||||
sig { returns(T.any(Time, ActiveSupport::TimeWithZone)) }
|
||||
sig { returns(Time) }
|
||||
def start_time
|
||||
@start_time
|
||||
end
|
||||
|
||||
@@ -98,25 +98,20 @@ module Tasks
|
||||
search_result, processed_blob =
|
||||
process_image_message_with_logging(bot, message, telegram_log)
|
||||
|
||||
if search_result && !search_result.empty?
|
||||
result_text = format_search_results(search_result)
|
||||
if search_result
|
||||
if search_result.empty?
|
||||
result_text = "❌ No close matches found."
|
||||
else
|
||||
result_text = format_search_results(search_result)
|
||||
end
|
||||
|
||||
# Update log with success
|
||||
# Update log with success (whether results found or not)
|
||||
update_telegram_log_success(
|
||||
telegram_log,
|
||||
search_result,
|
||||
result_text,
|
||||
processed_blob,
|
||||
)
|
||||
elsif search_result
|
||||
result_text = "❌ No close matches found."
|
||||
|
||||
# Update log with no results
|
||||
update_telegram_log_no_results(
|
||||
telegram_log,
|
||||
result_text,
|
||||
processed_blob,
|
||||
)
|
||||
else
|
||||
result_text =
|
||||
"❌ Could not process the image. Please make sure it's a valid image file."
|
||||
@@ -287,7 +282,7 @@ module Tasks
|
||||
telegram_last_name: user&.last_name,
|
||||
telegram_chat_id: chat.id,
|
||||
request_timestamp: Time.current,
|
||||
status: :success, # Will be updated later
|
||||
status: :processing, # Will be updated when request completes
|
||||
search_results_count: 0,
|
||||
response_data: {
|
||||
},
|
||||
@@ -332,30 +327,6 @@ module Tasks
|
||||
)
|
||||
end
|
||||
|
||||
sig do
|
||||
params(
|
||||
telegram_log: TelegramBotLog,
|
||||
response_text: String,
|
||||
processed_blob: T.nilable(BlobFile),
|
||||
).void
|
||||
end
|
||||
def update_telegram_log_no_results(
|
||||
telegram_log,
|
||||
response_text,
|
||||
processed_blob
|
||||
)
|
||||
telegram_log.update!(
|
||||
status: :no_results,
|
||||
search_results_count: 0,
|
||||
processed_image: processed_blob,
|
||||
response_data: {
|
||||
response_text: response_text,
|
||||
matches: 0,
|
||||
threshold: 90,
|
||||
},
|
||||
)
|
||||
end
|
||||
|
||||
sig { params(telegram_log: TelegramBotLog, response_text: String).void }
|
||||
def update_telegram_log_invalid_image(telegram_log, response_text)
|
||||
telegram_log.update!(
|
||||
|
||||
@@ -11,9 +11,9 @@ class TelegramBotLog < ReduxApplicationRecord
|
||||
# Status enum for tracking request outcomes
|
||||
enum :status,
|
||||
{
|
||||
processing: "processing",
|
||||
success: "success",
|
||||
error: "error",
|
||||
no_results: "no_results",
|
||||
invalid_image: "invalid_image",
|
||||
},
|
||||
prefix: true
|
||||
|
||||
@@ -106,19 +106,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-3 pr-4 text-sm">
|
||||
<% status_color = case log.status
|
||||
when "success"
|
||||
"bg-green-100 text-green-800"
|
||||
when "error"
|
||||
"bg-red-100 text-red-800"
|
||||
when "no_results"
|
||||
"bg-yellow-100 text-yellow-800"
|
||||
when "invalid_image"
|
||||
"bg-orange-100 text-orange-800"
|
||||
else
|
||||
"bg-slate-100 text-slate-800"
|
||||
end %>
|
||||
<span class="<%= status_color %> inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium">
|
||||
<span class="<%= status_color_class(log) %> inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium">
|
||||
<%= log.status.humanize %>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
@@ -58,19 +58,7 @@
|
||||
<div class="flex justify-between">
|
||||
<dt class="text-sm font-medium text-slate-500">Status</dt>
|
||||
<dd class="text-sm">
|
||||
<% status_color = case @telegram_bot_log.status
|
||||
when "success"
|
||||
"bg-green-100 text-green-800"
|
||||
when "error"
|
||||
"bg-red-100 text-red-800"
|
||||
when "no_results"
|
||||
"bg-yellow-100 text-yellow-800"
|
||||
when "invalid_image"
|
||||
"bg-orange-100 text-orange-800"
|
||||
else
|
||||
"bg-slate-100 text-slate-800"
|
||||
end %>
|
||||
<span class="<%= status_color %> inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium">
|
||||
<span class="<%= status_color_class(@telegram_bot_log) %> inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium">
|
||||
<%= @telegram_bot_log.status.humanize %>
|
||||
</span>
|
||||
</dd>
|
||||
|
||||
@@ -124,7 +124,7 @@ RSpec.describe TelegramBotLogsController, type: :controller do
|
||||
create(:telegram_bot_log, :successful, telegram_user_id: 456_789_123)
|
||||
end
|
||||
let!(:error_log) { create(:telegram_bot_log, :with_error) }
|
||||
let!(:no_results_log) { create(:telegram_bot_log, :no_results) }
|
||||
let!(:no_results_log) { create(:telegram_bot_log, :with_no_results) }
|
||||
|
||||
it "filters by telegram_user_id" do
|
||||
get :index, params: { telegram_user_id: "123456789" }
|
||||
|
||||
@@ -32,7 +32,7 @@ FactoryBot.define do
|
||||
end
|
||||
|
||||
trait :with_no_results do
|
||||
status { :no_results }
|
||||
status { :success }
|
||||
search_results_count { 0 }
|
||||
download_time { 0.07 }
|
||||
image_processing_time { 0.03 }
|
||||
@@ -66,6 +66,18 @@ FactoryBot.define do
|
||||
response_data { { error: "Unsupported format" } }
|
||||
end
|
||||
|
||||
trait :processing do
|
||||
status { :processing }
|
||||
search_results_count { 0 }
|
||||
download_time { nil }
|
||||
image_processing_time { nil }
|
||||
fingerprint_computation_time { nil }
|
||||
search_computation_time { nil }
|
||||
total_request_time { nil }
|
||||
error_message { nil }
|
||||
response_data { {} }
|
||||
end
|
||||
|
||||
trait :minimal_user_info do
|
||||
telegram_username { nil }
|
||||
telegram_first_name { nil }
|
||||
|
||||
46
spec/helpers/telegram_bot_logs_helper_spec.rb
Normal file
46
spec/helpers/telegram_bot_logs_helper_spec.rb
Normal file
@@ -0,0 +1,46 @@
|
||||
# typed: false
|
||||
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe TelegramBotLogsHelper, type: :helper do
|
||||
describe "#status_color_class" do
|
||||
it "returns blue classes for processing status" do
|
||||
log = build(:telegram_bot_log, :processing)
|
||||
expect(helper.status_color_class(log)).to eq("bg-blue-100 text-blue-800")
|
||||
end
|
||||
|
||||
it "returns green classes for success status" do
|
||||
log = build(:telegram_bot_log, :successful)
|
||||
expect(helper.status_color_class(log)).to eq(
|
||||
"bg-green-100 text-green-800",
|
||||
)
|
||||
end
|
||||
|
||||
it "returns red classes for error status" do
|
||||
log = build(:telegram_bot_log, :with_error)
|
||||
expect(helper.status_color_class(log)).to eq("bg-red-100 text-red-800")
|
||||
end
|
||||
|
||||
it "returns orange classes for invalid_image status" do
|
||||
log = build(:telegram_bot_log, :invalid_image)
|
||||
expect(helper.status_color_class(log)).to eq(
|
||||
"bg-orange-100 text-orange-800",
|
||||
)
|
||||
end
|
||||
|
||||
it "returns slate classes for unknown status" do
|
||||
log = build(:telegram_bot_log)
|
||||
allow(log).to receive(:status).and_return("unknown_status")
|
||||
expect(helper.status_color_class(log)).to eq(
|
||||
"bg-slate-100 text-slate-800",
|
||||
)
|
||||
end
|
||||
|
||||
it "handles success status with no results" do
|
||||
log = build(:telegram_bot_log, :with_no_results)
|
||||
expect(helper.status_color_class(log)).to eq(
|
||||
"bg-green-100 text-green-800",
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -37,9 +37,9 @@ RSpec.describe TelegramBotLog, type: :model do
|
||||
it do
|
||||
should define_enum_for(:status)
|
||||
.with_values(
|
||||
processing: "processing",
|
||||
success: "success",
|
||||
error: "error",
|
||||
no_results: "no_results",
|
||||
invalid_image: "invalid_image",
|
||||
)
|
||||
.backed_by_column_of_type(:string)
|
||||
@@ -205,8 +205,13 @@ RSpec.describe TelegramBotLog, type: :model do
|
||||
describe ".successful" do
|
||||
it "returns only successful logs" do
|
||||
successful_logs = TelegramBotLog.successful
|
||||
expect(successful_logs).to include(user1_log1, user2_log, recent_log)
|
||||
expect(successful_logs).not_to include(user1_log2, no_results_log)
|
||||
expect(successful_logs).to include(
|
||||
user1_log1,
|
||||
user2_log,
|
||||
recent_log,
|
||||
no_results_log,
|
||||
)
|
||||
expect(successful_logs).not_to include(user1_log2)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -401,6 +406,15 @@ RSpec.describe TelegramBotLog, type: :model do
|
||||
expect(log.has_performance_metrics?).to be false
|
||||
end
|
||||
|
||||
it "creates processing log with correct attributes" do
|
||||
log = build(:telegram_bot_log, :processing)
|
||||
expect(log.status).to eq("processing")
|
||||
expect(log.search_results_count).to eq(0)
|
||||
expect(log.error_message).to be_nil
|
||||
expect(log.has_performance_metrics?).to be false
|
||||
expect(log.total_request_time).to be_nil
|
||||
end
|
||||
|
||||
it "creates log with image association" do
|
||||
log = build(:telegram_bot_log, :with_image)
|
||||
expect(log.processed_image).to be_present
|
||||
|
||||
Reference in New Issue
Block a user