From 7bba2909f205fd71ba9d57235c94d739cd1023ff Mon Sep 17 00:00:00 2001 From: Josh Date: Sat, 21 Dec 2024 15:47:17 +0530 Subject: [PATCH 1/2] changes in rage service --- .../app/services/RageClickService/detector.rb | 24 +++++++++---------- .../app/services/RageClickService/result.rb | 2 +- .../app/services/events_service/create.rb | 16 ++++++++++++- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/ruby-api/app/services/RageClickService/detector.rb b/ruby-api/app/services/RageClickService/detector.rb index 661d8fa..94b795f 100644 --- a/ruby-api/app/services/RageClickService/detector.rb +++ b/ruby-api/app/services/RageClickService/detector.rb @@ -25,7 +25,7 @@ def analyze_clicks(user_events) if rage_click?(interactions) results << { action_id: action_id, - uid: interactions.first["uid"], + uid: interactions.first["uid".to_sym], confidence_score: calculate_confidence_score(interactions), total_clicks: interactions.length, avg_time_between_clicks: average_time_between_clicks(interactions) @@ -59,21 +59,21 @@ def validate_row!(row, index) required_fields = ['uid', 'captured_at', 'action_id'] required_fields.each do |field| - if row[field].nil? + if row[field.to_sym].nil? raise InvalidDataError, "Missing required field '#{field}' at index #{index}" end end # Validate timestamp format begin - DateTime.parse(row['captured_at'].to_s) + DateTime.parse(row['captured_at'.to_sym].to_s) rescue ArgumentError raise InvalidDataError, "Invalid timestamp format at index #{index}" end end def grouped_by_user_action(data) - data.group_by { |row| [row['action_id']] } + data.group_by { |row| [row['action_id'.to_sym]] } end def parse_timestamp(timestamp_str) @@ -88,7 +88,7 @@ def rage_click?(interactions) # Sort interactions by timestamp sorted_interactions = interactions - .map { |i| [i, parse_timestamp(i['captured_at'])] } + .map { |i| [i, parse_timestamp(i['captured_at'.to_sym])] } .reject { |_, timestamp| timestamp.nil? } .sort_by { |_, timestamp| timestamp } .map(&:first) @@ -97,8 +97,8 @@ def rage_click?(interactions) # Check for rapid successive clicks within time window sorted_interactions.each_cons(min_clicks) do |window| - first_time = parse_timestamp(window.first['captured_at']) - last_time = parse_timestamp(window.last['captured_at']) + first_time = parse_timestamp(window.first['captured_at'.to_sym]) + last_time = parse_timestamp(window.last['captured_at'.to_sym]) next if first_time.nil? || last_time.nil? @@ -112,7 +112,7 @@ def rage_click?(interactions) def calculate_confidence_score(interactions) # Sort interactions by timestamp sorted_interactions = interactions - .map { |i| [i, parse_timestamp(i['captured_at'])] } + .map { |i| [i, parse_timestamp(i['captured_at'.to_sym])] } .reject { |_, timestamp| timestamp.nil? } .sort_by { |_, timestamp| timestamp } .map(&:first) @@ -139,7 +139,7 @@ def calculate_confidence_score(interactions) def calculate_click_frequency_score(interactions) return 0.0 if interactions.length < 2 - times = interactions.map { |i| parse_timestamp(i['captured_at']) }.compact + times = interactions.map { |i| parse_timestamp(i['captured_at'.to_sym]) }.compact return 0.0 if times.length < 2 intervals = times.each_cons(2).map { |t1, t2| ((t2 - t1) * 24 * 60 * 60).to_i } @@ -155,7 +155,7 @@ def calculate_click_frequency_score(interactions) def calculate_click_consistency_score(interactions) return 0.0 if interactions.length < 3 - times = interactions.map { |i| parse_timestamp(i['captured_at']) }.compact + times = interactions.map { |i| parse_timestamp(i['captured_at'.to_sym]) }.compact return 0.0 if times.length < 3 intervals = times.each_cons(2).map { |t1, t2| ((t2 - t1) * 24 * 60 * 60).to_i } @@ -180,7 +180,7 @@ def calculate_total_clicks_score(interactions) def average_time_between_clicks(interactions) return 0.0 if interactions.length < 2 - times = interactions.map { |i| parse_timestamp(i['captured_at']) }.compact + times = interactions.map { |i| parse_timestamp(i['captured_at'.to_sym]) }.compact return 0.0 if times.length < 2 intervals = times.each_cons(2).map { |t1, t2| ((t2 - t1) * 24 * 60 * 60).to_i } @@ -189,4 +189,4 @@ def average_time_between_clicks(interactions) intervals.sum.to_f / intervals.length end end -end \ No newline at end of file +end diff --git a/ruby-api/app/services/RageClickService/result.rb b/ruby-api/app/services/RageClickService/result.rb index ad5db76..a37a7ca 100644 --- a/ruby-api/app/services/RageClickService/result.rb +++ b/ruby-api/app/services/RageClickService/result.rb @@ -42,4 +42,4 @@ def average_confidence_score def no_of_occurances end end -end \ No newline at end of file +end diff --git a/ruby-api/app/services/events_service/create.rb b/ruby-api/app/services/events_service/create.rb index 5982837..caa2923 100644 --- a/ruby-api/app/services/events_service/create.rb +++ b/ruby-api/app/services/events_service/create.rb @@ -12,14 +12,24 @@ def call user_event_params = build_user_event_params(event_param, action) user_event = UserEvent.create!(user_event_params) +<<<<<<< Updated upstream res = action&.user_events&.where(uid: event_param[:uid], captured_at: 5.seconds.ago..user_event.captured_at.to_datetime.utc) if res && res.count == 5 rage_click_event = create_aggregate_event(user_event, action) rage_event_ids << rage_click_event.id end +======= + @user_events = [] + @user_events << user_event + # if action.user_events.where(uid: event_param[:uid], captured_at: 5.seconds.ago..DateTime.current).count == 5 + # rage_click_event = create_aggregate_event(user_event, action) + # rage_event_ids << rage_click_event.id + # end +>>>>>>> Stashed changes end - rage_event_ids + rage_click = RageClickService::Detector.new().analyze_clicks(@user_events) + AggregateEvent.create!(aggregate_event_params(rage_click)) end rescue ActiveRecord::RecordInvalid => e # Handle transaction failure if necessary (e.g., log or raise an error) @@ -28,6 +38,10 @@ def call private + def aggregate_event_params(rage_click) + + end + def find_action(param) Action.find_or_create_by(url: param[:url], element: param[:element_id], action: param[:action]) end From 8d8a7e4eb759de4ad5047da7b5f11a243c7fdace Mon Sep 17 00:00:00 2001 From: Shubhh Date: Sat, 21 Dec 2024 16:42:55 +0530 Subject: [PATCH 2/2] integrated code with rage_click_service for creating aggregate events --- .../app/services/RageClickService/detector.rb | 22 +++++++-------- .../app/services/events_service/create.rb | 27 ++++++++++--------- .../20241221100253_drop_unvanted_tables.rb | 2 +- ruby-api/db/schema.rb | 8 ++++++ 4 files changed, 34 insertions(+), 25 deletions(-) diff --git a/ruby-api/app/services/RageClickService/detector.rb b/ruby-api/app/services/RageClickService/detector.rb index 94b795f..9a24d4c 100644 --- a/ruby-api/app/services/RageClickService/detector.rb +++ b/ruby-api/app/services/RageClickService/detector.rb @@ -25,7 +25,7 @@ def analyze_clicks(user_events) if rage_click?(interactions) results << { action_id: action_id, - uid: interactions.first["uid".to_sym], + uid: interactions.first["uid"], confidence_score: calculate_confidence_score(interactions), total_clicks: interactions.length, avg_time_between_clicks: average_time_between_clicks(interactions) @@ -59,21 +59,21 @@ def validate_row!(row, index) required_fields = ['uid', 'captured_at', 'action_id'] required_fields.each do |field| - if row[field.to_sym].nil? + if row[field].nil? raise InvalidDataError, "Missing required field '#{field}' at index #{index}" end end # Validate timestamp format begin - DateTime.parse(row['captured_at'.to_sym].to_s) + DateTime.parse(row['captured_at'].to_s) rescue ArgumentError raise InvalidDataError, "Invalid timestamp format at index #{index}" end end def grouped_by_user_action(data) - data.group_by { |row| [row['action_id'.to_sym]] } + data.group_by { |row| [row['action_id']] } end def parse_timestamp(timestamp_str) @@ -88,7 +88,7 @@ def rage_click?(interactions) # Sort interactions by timestamp sorted_interactions = interactions - .map { |i| [i, parse_timestamp(i['captured_at'.to_sym])] } + .map { |i| [i, parse_timestamp(i['captured_at'])] } .reject { |_, timestamp| timestamp.nil? } .sort_by { |_, timestamp| timestamp } .map(&:first) @@ -97,8 +97,8 @@ def rage_click?(interactions) # Check for rapid successive clicks within time window sorted_interactions.each_cons(min_clicks) do |window| - first_time = parse_timestamp(window.first['captured_at'.to_sym]) - last_time = parse_timestamp(window.last['captured_at'.to_sym]) + first_time = parse_timestamp(window.first['captured_at']) + last_time = parse_timestamp(window.last['captured_at']) next if first_time.nil? || last_time.nil? @@ -112,7 +112,7 @@ def rage_click?(interactions) def calculate_confidence_score(interactions) # Sort interactions by timestamp sorted_interactions = interactions - .map { |i| [i, parse_timestamp(i['captured_at'.to_sym])] } + .map { |i| [i, parse_timestamp(i['captured_at'])] } .reject { |_, timestamp| timestamp.nil? } .sort_by { |_, timestamp| timestamp } .map(&:first) @@ -139,7 +139,7 @@ def calculate_confidence_score(interactions) def calculate_click_frequency_score(interactions) return 0.0 if interactions.length < 2 - times = interactions.map { |i| parse_timestamp(i['captured_at'.to_sym]) }.compact + times = interactions.map { |i| parse_timestamp(i['captured_at']) }.compact return 0.0 if times.length < 2 intervals = times.each_cons(2).map { |t1, t2| ((t2 - t1) * 24 * 60 * 60).to_i } @@ -155,7 +155,7 @@ def calculate_click_frequency_score(interactions) def calculate_click_consistency_score(interactions) return 0.0 if interactions.length < 3 - times = interactions.map { |i| parse_timestamp(i['captured_at'.to_sym]) }.compact + times = interactions.map { |i| parse_timestamp(i['captured_at']) }.compact return 0.0 if times.length < 3 intervals = times.each_cons(2).map { |t1, t2| ((t2 - t1) * 24 * 60 * 60).to_i } @@ -180,7 +180,7 @@ def calculate_total_clicks_score(interactions) def average_time_between_clicks(interactions) return 0.0 if interactions.length < 2 - times = interactions.map { |i| parse_timestamp(i['captured_at'.to_sym]) }.compact + times = interactions.map { |i| parse_timestamp(i['captured_at']) }.compact return 0.0 if times.length < 2 intervals = times.each_cons(2).map { |t1, t2| ((t2 - t1) * 24 * 60 * 60).to_i } diff --git a/ruby-api/app/services/events_service/create.rb b/ruby-api/app/services/events_service/create.rb index caa2923..3700334 100644 --- a/ruby-api/app/services/events_service/create.rb +++ b/ruby-api/app/services/events_service/create.rb @@ -12,24 +12,25 @@ def call user_event_params = build_user_event_params(event_param, action) user_event = UserEvent.create!(user_event_params) -<<<<<<< Updated upstream + + user_events = [] + user_events << user_event + user_event_hashes = user_events.map(&:attributes) + rage_click = RageClickService::Detector.new().analyze_clicks(user_event_hashes) + + if rage_click.rage_clicks.present? + aggregate_event_param = aggregate_event_params(rage_click.rage_clicks) + aggregate_event_param.each do |param| + AggregateEvent.create!(param) + end + end res = action&.user_events&.where(uid: event_param[:uid], captured_at: 5.seconds.ago..user_event.captured_at.to_datetime.utc) if res && res.count == 5 rage_click_event = create_aggregate_event(user_event, action) rage_event_ids << rage_click_event.id end -======= - @user_events = [] - @user_events << user_event - # if action.user_events.where(uid: event_param[:uid], captured_at: 5.seconds.ago..DateTime.current).count == 5 - # rage_click_event = create_aggregate_event(user_event, action) - # rage_event_ids << rage_click_event.id - # end ->>>>>>> Stashed changes end - rage_click = RageClickService::Detector.new().analyze_clicks(@user_events) - AggregateEvent.create!(aggregate_event_params(rage_click)) end rescue ActiveRecord::RecordInvalid => e # Handle transaction failure if necessary (e.g., log or raise an error) @@ -38,8 +39,8 @@ def call private - def aggregate_event_params(rage_click) - + def aggregate_event_params(rage_clicks) + rage_clicks.map { |hash| hash.slice(:action_id, :uid) } end def find_action(param) diff --git a/ruby-api/db/migrate/20241221100253_drop_unvanted_tables.rb b/ruby-api/db/migrate/20241221100253_drop_unvanted_tables.rb index ce66fa0..1381ee0 100644 --- a/ruby-api/db/migrate/20241221100253_drop_unvanted_tables.rb +++ b/ruby-api/db/migrate/20241221100253_drop_unvanted_tables.rb @@ -1,6 +1,6 @@ class DropUnvantedTables < ActiveRecord::Migration[7.2] def change drop_table :events - drop_table :event_aggregations + execute "DROP TABLE event_aggregations CASCADE;" end end diff --git a/ruby-api/db/schema.rb b/ruby-api/db/schema.rb index 7fbd4fd..6da5fb4 100644 --- a/ruby-api/db/schema.rb +++ b/ruby-api/db/schema.rb @@ -33,6 +33,14 @@ t.index ["user_event_id"], name: "index_aggregate_events_on_user_event_id" end + create_table "images", force: :cascade do |t| + t.string "attachement" + t.bigint "event_aggregation_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["event_aggregation_id"], name: "index_images_on_event_aggregation_id" + end + create_table "user_events", force: :cascade do |t| t.datetime "captured_at" t.text "user_agent"