Aggiunge heatmaps first-party (click/scroll) con pagina admin Analytics.
Raccoglie eventi aggregati dietro consenso cookie, senza PII né tracking su admin/regia/live/replay; GA4 resta invariato. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Analytics
|
||||
class PathNormalizer
|
||||
UUID_RE = /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i
|
||||
NUMERIC_RE = /\A\d{6,}\z/
|
||||
TOKENISH_RE = /\A[A-Za-z0-9_\-]{22,}\z/
|
||||
|
||||
EXCLUDED_PREFIXES = %w[/admin /regia /analytics /cable /api /webhooks /internal].freeze
|
||||
|
||||
class << self
|
||||
def normalize(raw_path)
|
||||
path = raw_path.to_s.split("?", 2).first.to_s
|
||||
path = "/" if path.blank?
|
||||
path = "/#{path}" unless path.start_with?("/")
|
||||
path = path.gsub(%r{/{2,}}, "/").chomp("/")
|
||||
path = "/" if path.blank?
|
||||
|
||||
parts = path.split("/").map do |segment|
|
||||
next segment if segment.blank?
|
||||
next ":id" if UUID_RE.match?(segment)
|
||||
next ":id" if NUMERIC_RE.match?(segment)
|
||||
next ":token" if TOKENISH_RE.match?(segment) && segment.match?(/[A-Z]/)
|
||||
|
||||
segment
|
||||
end
|
||||
normalized = parts.join("/")
|
||||
normalized = "/" if normalized.blank?
|
||||
normalized
|
||||
end
|
||||
|
||||
def excluded?(raw_or_normalized)
|
||||
path = normalize(raw_or_normalized)
|
||||
return true if EXCLUDED_PREFIXES.any? { |p| path == p || path.start_with?("#{p}/") }
|
||||
return true if path.match?(%r{\A/live/[^/]+})
|
||||
return true if path.match?(%r{\A/replay/[^/]+})
|
||||
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user