Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 25 additions & 8 deletions app/controllers/static_pages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ def index

# Process results to get sorted languages and editors
language_counts = results
.map { |r| [ r.language&.downcase, r.language_count ] }
.map { |r| [ r.language&.categorize_language, r.language_count ] } # fix the bug where langs can have both upper and lower case like JAVA and java found here (https://github.com/hackclub/hackatime/issues/402)
.reject { |lang, _| lang.nil? || lang.empty? }
.group_by { |lang, _| lang }
.transform_values { |pairs| pairs.sum { |_, count| count } }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Calling Hash#uniq on language_counts will raise a NoMethodError, crashing the application.
Severity: CRITICAL | Confidence: High

🔍 Detailed Analysis

The language_counts calculation attempts to call .uniq on a Hash object after group_by and transform_values have been applied. The Hash#uniq method does not exist in Ruby, leading to a NoMethodError. This error will occur every time a logged-in user with heartbeats visits the public-facing homepage, causing the application to crash.

💡 Suggested Fix

Remove the .uniq call from line 52. The group_by and transform_values operations already produce a deduplicated Hash with unique language keys and aggregated counts, making .uniq redundant and incorrect.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: app/controllers/static_pages_controller.rb#L51

Potential issue: The `language_counts` calculation attempts to call `.uniq` on a Hash
object after `group_by` and `transform_values` have been applied. The `Hash#uniq` method
does not exist in Ruby, leading to a `NoMethodError`. This error will occur every time a
logged-in user with heartbeats visits the public-facing homepage, causing the
application to crash.

Did we get this right? 👍 / 👎 to inform future reviews.
Reference ID: 6043025

.uniq
.sort_by { |_, count| -count }

Expand Down Expand Up @@ -271,12 +273,10 @@ def dashboard
.reverse.map(&:first)
.compact_blank
.map { |k|
if filter == :editor
ApplicationController.helpers.display_editor_name(k)
elsif filter == :operating_system
ApplicationController.helpers.display_os_name(k)
elsif filter == :language
ApplicationController.helpers.display_language_name(k)
if filter == :language
k.categorize_language
elsif %i[operating_system editor].include?(filter)
k.capitalize
else
k
Comment on lines +277 to 281
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change replaces the display_editor_name helper with a simple .capitalize call, which will produce incorrect results. For example, display_editor_name('vscode') correctly returns 'VS Code', but 'vscode'.capitalize returns 'Vscode'. This breaks the visual display of editor names. Use the helper method instead to maintain correct formatting.
Severity: HIGH

🤖 Prompt for AI Agent

Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: app/controllers/static_pages_controller.rb#L277-L281

Potential issue: This change replaces the `display_editor_name` helper with a simple
`.capitalize` call, which will produce incorrect results. For example,
`display_editor_name('vscode')` correctly returns 'VS Code', but `'vscode'.capitalize`
returns 'Vscode'. This breaks the visual display of editor names. Use the helper method
instead to maintain correct formatting.

Did we get this right? 👍 / 👎 to inform future reviews.
Reference ID: 6043025

end
Expand All @@ -289,6 +289,18 @@ def dashboard
# search for both lowercase and capitalized versions
normalized_arr = filter_arr.flat_map { |v| [ v.downcase, v.capitalize ] }.uniq
filtered_heartbeats = filtered_heartbeats.where(filter => normalized_arr)
elsif filter == :language
# find the real name, not the pretty one cause some edditors are stupid and return stuff like JAVASCRIPT and javascript and i need to add stuff to make them both fit the lookup
raw_language_values = []
current_user.heartbeats.distinct.pluck(filter).compact_blank.each do |raw_lang|
categorized = raw_lang.categorize_language
if filter_arr.include?(categorized)
raw_language_values << raw_lang
end
end
Rails.logger.debug "lang filter: selected=#{filter_arr}, raw_language_values=#{raw_language_values}" # Debug line

Comment on lines 291 to +302
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The language filtering logic (lines 291-302) is inefficient because it retrieves all raw language values from the database in-memory and then filters them in Ruby. This approach doesn't scale well and performs unnecessary database queries. Consider building a database query that filters on the categorized language values instead, or using a scope/helper method. The current implementation also lacks error handling if categorize_language behaves unexpectedly.
Severity: MEDIUM

🤖 Prompt for AI Agent

Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: app/controllers/static_pages_controller.rb#L291-L302

Potential issue: The language filtering logic (lines 291-302) is inefficient because it
retrieves all raw language values from the database in-memory and then filters them in
Ruby. This approach doesn't scale well and performs unnecessary database queries.
Consider building a database query that filters on the categorized language values
instead, or using a scope/helper method. The current implementation also lacks error
handling if `categorize_language` behaves unexpectedly.

Did we get this right? 👍 / 👎 to inform future reviews.
Reference ID: 6043025

filtered_heartbeats = filtered_heartbeats.where(filter => raw_language_values) if raw_language_values.any?
else
filtered_heartbeats = filtered_heartbeats.where(filter => filter_arr)
end
Expand Down Expand Up @@ -335,7 +347,12 @@ def dashboard
.duration_seconds
.each_with_object({}) do |(raw_key, duration), agg|
key = raw_key.to_s.presence || "Unknown"
key = key.downcase if %i[editor operating_system].include?(filter)
# fix the bug where langs can have both upper and lower case like JAVA and java found here (https://github.com/hackclub/hackatime/issues/402)
if filter == :language
key = key.categorize_language unless key == "Unknown"
elsif %i[editor operating_system].include?(filter)
key = key.downcase
end
agg[key] = (agg[key] || 0) + duration
Comment on lines +354 to 356
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 354 uses .downcase for editor and operating_system, but this is inconsistent with the display_editor_name and display_os_name helpers which provide proper capitalization (e.g., 'vscode' -> 'VS Code', 'darwin' -> 'macOS'). To be consistent with the dashboard section above and maintain correct aggregation, you should apply the same normalization logic. Consider using a helper method or applying the same categorization approach used for languages.
Severity: MEDIUM

🤖 Prompt for AI Agent

Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: app/controllers/static_pages_controller.rb#L354-L356

Potential issue: Line 354 uses `.downcase` for editor and operating_system, but this is
inconsistent with the display_editor_name and display_os_name helpers which provide
proper capitalization (e.g., 'vscode' -> 'VS Code', 'darwin' -> 'macOS'). To be
consistent with the dashboard section above and maintain correct aggregation, you should
apply the same normalization logic. Consider using a helper method or applying the same
categorization approach used for languages.

Did we get this right? 👍 / 👎 to inform future reviews.
Reference ID: 6043025

end

Comment on lines +351 to 358
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the pie chart data section, when normalizing language keys, the code uses key.categorize_language but then later passes it to display_language_name for labeling. This creates a potential disconnect: categorize_language is designed for standardization (lowercase -> standardized form), but display_language_name expects the standardized form and provides UI-specific formatting. Ensure these two methods work well together and document the expectation. For consistency, consider whether languages should be stored as their raw form or categorized form.
Severity: MEDIUM

🤖 Prompt for AI Agent

Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: app/controllers/static_pages_controller.rb#L351-L358

Potential issue: In the pie chart data section, when normalizing language keys, the code
uses `key.categorize_language` but then later passes it to `display_language_name` for
labeling. This creates a potential disconnect: `categorize_language` is designed for
standardization (lowercase -> standardized form), but `display_language_name` expects
the standardized form and provides UI-specific formatting. Ensure these two methods work
well together and document the expectation. For consistency, consider whether languages
should be stored as their raw form or categorized form.

Did we get this right? 👍 / 👎 to inform future reviews.
Reference ID: 6043025

Expand Down
9 changes: 9 additions & 0 deletions config/initializers/monkey_patches.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,12 @@ def user
scope :with_future, -> { unscope(where: :created_at) }
end
end



class String
# Hopefully this is the right place! It a really good monkey patch!!
def categorize_language
WakatimeService.categorize_language(self)
end
end
27 changes: 27 additions & 0 deletions lib/wakatime_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,33 @@ def transform_display_name(group_by, key)
end
end

def self.categorize_language(language)
# Stole this list of langs from some wikipidia page abt popular langs tehe
# Please double check this list and add others that i missed or added wrong
return nil if language.blank?

case language.downcase
when "java" then "Java"
when "javascript", "js" then "JavaScript"
when "typescript", "ts" then "TypeScript"
when "python", "py", "python3" then "Python"
when "c++", "cpp" then "C++"
when "c#", "csharp" then "C#"
when "html" then "HTML"
when "css" then "CSS"
when "json" then "JSON"
when "xml" then "XML"
when "yaml", "yml" then "YAML"
when "markdown", "md" then "Markdown"
when "shell", "bash", "sh" then "Shell"
when "ruby", "rb" then "Ruby"
when "go", "golang" then "Go"
when "rust", "rs" then "Rust"
when "php" then "PHP"
else language.capitalize
end
end

private

def convert_to_unix_timestamp(timestamp)
Expand Down