Tidy up homepage and navigation

This commit is contained in:
Dan Milne
2025-11-09 20:58:13 +11:00
parent c9e2992fe0
commit 1f4428348d
56 changed files with 2822 additions and 955 deletions

18
app/models/dsn.rb Normal file
View File

@@ -0,0 +1,18 @@
class Dsn < ApplicationRecord
validates :key, presence: true, uniqueness: true
validates :name, presence: true
before_validation :generate_key, on: :create
scope :enabled, -> { where(enabled: true) }
def self.authenticate(key)
enabled.find_by(key: key)
end
private
def generate_key
self.key ||= SecureRandom.hex(32)
end
end

View File

@@ -1,8 +1,6 @@
# frozen_string_literal: true
class Event < ApplicationRecord
belongs_to :project
# Normalized association for hosts (most valuable compression)
belongs_to :request_host, optional: true
@@ -87,13 +85,12 @@ class Event < ApplicationRecord
# Normalize event fields after extraction
after_validation :normalize_event_fields, if: :should_normalize?
def self.create_from_waf_payload!(event_id, payload, project)
def self.create_from_waf_payload!(event_id, payload)
# Normalize headers in payload during import phase
normalized_payload = normalize_payload_headers(payload)
# Create the WAF request event
create!(
project: project,
event_id: event_id,
timestamp: parse_timestamp(normalized_payload["timestamp"]),
payload: normalized_payload,

View File

@@ -1,7 +1,6 @@
# frozen_string_literal: true
class Issue < ApplicationRecord
belongs_to :project
has_many :events, dependent: :nullify
enum :status, { open: 0, resolved: 1, ignored: 2 }
@@ -17,18 +16,18 @@ class Issue < ApplicationRecord
# Real-time updates
after_create_commit do
broadcast_refresh_to(project)
broadcast_refresh
end
after_update_commit do
broadcast_refresh # Refreshes the issue show page
broadcast_refresh_to(project, "issues") # Refreshes the project's issues index
broadcast_refresh_to("issues") # Refreshes the issues index
end
def self.group_event(event_payload, project)
def self.group_event(event_payload)
fingerprint = generate_fingerprint(event_payload)
find_or_create_by(project: project, fingerprint: fingerprint) do |issue|
find_or_create_by(fingerprint: fingerprint) do |issue|
issue.title = extract_title(event_payload)
issue.exception_type = extract_exception_type(event_payload)
issue.first_seen = Time.current

View File

@@ -29,6 +29,8 @@ class NetworkRange < ApplicationRecord
scope :vpn, -> { where(is_vpn: true) }
scope :user_created, -> { where(source: 'user_created') }
scope :api_imported, -> { where(source: 'api_imported') }
scope :with_events, -> { where("events_count > 0") }
scope :most_active, -> { order(events_count: :desc) }
# Callbacks
before_validation :set_default_source
@@ -237,9 +239,10 @@ class NetworkRange < ApplicationRecord
cidr.to_s.gsub('/', '_')
end
# Analytics methods
# Analytics methods - events_count is now a counter cache column maintained by database triggers
# This is much more performant than the previous implementation that did complex network queries
def events_count
Event.where(ip_address: child_ranges.pluck(:network_address) + [network_address]).count
self[:events_count] || 0
end
def recent_events(limit: 100)