Let's fix WakaTimeError (#1125)

This commit is contained in:
Mahad Kalam 2026-04-01 13:39:55 +01:00 committed by GitHub
parent b2af327466
commit e43cdc5ea1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 108 additions and 1 deletions

View file

@ -282,7 +282,16 @@ class Api::Hackatime::V1::HackatimeController < ApplicationController
}).slice(*Heartbeat.column_names.map(&:to_sym)) }).slice(*Heartbeat.column_names.map(&:to_sym))
# ^^ They say safety laws are written in blood. Well, so is this line! # ^^ They say safety laws are written in blood. Well, so is this line!
# Basically this filters out columns that aren't in our DB (the biggest one being raw_data) # Basically this filters out columns that aren't in our DB (the biggest one being raw_data)
new_heartbeat = Heartbeat.find_or_create_by(attrs) begin
new_heartbeat = Heartbeat.find_or_create_by(attrs)
rescue ActiveRecord::RecordNotUnique
# Duplicate heartbeat (same fields_hash) exists but wasn't found because
# a non-indexed attribute differs (e.g., ip_address changed between requests).
temp = Heartbeat.new(attrs)
hash = Heartbeat.generate_fields_hash(temp.attributes)
new_heartbeat = @user.heartbeats.find_by(fields_hash: hash)
raise unless new_heartbeat
end
queue_project_mapping(heartbeat[:project]) queue_project_mapping(heartbeat[:project])
results << [ new_heartbeat.attributes, 201 ] results << [ new_heartbeat.attributes, 201 ]

View file

@ -131,6 +131,104 @@ class Api::Hackatime::V1::HackatimeControllerTest < ActionDispatch::IntegrationT
assert_equal "Ruby", heartbeat.language assert_equal "Ruby", heartbeat.language
end end
test "single heartbeat ignores unknown fields like raw_data and ai_line_changes" do
user = User.create!(timezone: "UTC")
api_key = user.api_keys.create!(name: "primary")
payload = {
entity: "src/main.rb",
plugin: "vscode/1.131.0 vscode-wakatime/29.0.3",
project: "hackatime",
time: Time.current.to_f,
type: "file",
raw_data: '{"some": "data"}',
ai_line_changes: 5,
human_line_changes: 10,
completely_bogus_field: "should be ignored"
}
assert_difference("Heartbeat.count", 1) do
post "/api/hackatime/v1/users/current/heartbeats",
params: payload.to_json,
headers: {
"Authorization" => "Bearer #{api_key.token}",
"CONTENT_TYPE" => "text/plain"
}
end
assert_response :accepted
heartbeat = Heartbeat.order(:id).last
assert_equal "src/main.rb", heartbeat.entity
assert_equal "hackatime", heartbeat.project
end
test "bulk heartbeat ignores unknown fields like raw_data and ai_line_changes" do
user = User.create!(timezone: "UTC")
api_key = user.api_keys.create!(name: "primary")
payload = [
{
entity: "src/first.rb",
plugin: "vscode/1.131.0 vscode-wakatime/29.0.3",
project: "hackatime",
time: Time.current.to_f,
type: "file",
raw_data: '{"some": "data"}',
ai_line_changes: 3,
human_line_changes: 7
}
]
assert_difference("Heartbeat.count", 1) do
post "/api/hackatime/v1/users/current/heartbeats.bulk",
params: payload.to_json,
headers: {
"Authorization" => "Bearer #{api_key.token}",
"CONTENT_TYPE" => "application/json"
}
end
assert_response :created
heartbeat = Heartbeat.order(:id).last
assert_equal "src/first.rb", heartbeat.entity
assert_equal "hackatime", heartbeat.project
end
test "duplicate heartbeat with different ip returns existing record" do
user = User.create!(timezone: "UTC")
api_key = user.api_keys.create!(name: "primary")
payload = {
entity: "src/main.rb",
plugin: "vscode/1.0.0",
project: "hackatime",
time: Time.current.to_f,
type: "file"
}
# First request creates the heartbeat
assert_difference("Heartbeat.count", 1) do
post "/api/hackatime/v1/users/current/heartbeats",
params: payload.to_json,
headers: {
"Authorization" => "Bearer #{api_key.token}",
"CONTENT_TYPE" => "text/plain"
}
end
assert_response :accepted
# Second request with same data should not create a duplicate
assert_no_difference("Heartbeat.count") do
post "/api/hackatime/v1/users/current/heartbeats",
params: payload.to_json,
headers: {
"Authorization" => "Bearer #{api_key.token}",
"CONTENT_TYPE" => "text/plain"
}
end
assert_response :accepted
end
test "bulk heartbeat normalizes permitted params" do test "bulk heartbeat normalizes permitted params" do
user = User.create!(timezone: "UTC") user = User.create!(timezone: "UTC")
api_key = user.api_keys.create!(name: "primary") api_key = user.api_keys.create!(name: "primary")