First commit!
This commit is contained in:
97
app/models/issue.rb
Normal file
97
app/models/issue.rb
Normal file
@@ -0,0 +1,97 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Issue < ApplicationRecord
|
||||
belongs_to :project
|
||||
has_many :events, dependent: :nullify
|
||||
|
||||
enum :status, { open: 0, resolved: 1, ignored: 2 }
|
||||
|
||||
validates :title, presence: true
|
||||
|
||||
scope :recent, -> { order(last_seen: :desc) }
|
||||
scope :by_frequency, -> { order(count: :desc) }
|
||||
|
||||
# Callbacks for email notifications
|
||||
after_create :notify_new_issue, if: :should_notify_new_issue?
|
||||
after_update :notify_issue_reopened, if: :was_reopened?
|
||||
|
||||
# Real-time updates
|
||||
after_create_commit do
|
||||
broadcast_refresh_to(project)
|
||||
end
|
||||
|
||||
after_update_commit do
|
||||
broadcast_refresh # Refreshes the issue show page
|
||||
broadcast_refresh_to(project, "issues") # Refreshes the project's issues index
|
||||
end
|
||||
|
||||
def self.group_event(event_payload, project)
|
||||
fingerprint = generate_fingerprint(event_payload)
|
||||
|
||||
find_or_create_by(project: project, fingerprint: fingerprint) do |issue|
|
||||
issue.title = extract_title(event_payload)
|
||||
issue.exception_type = extract_exception_type(event_payload)
|
||||
issue.first_seen = Time.current
|
||||
issue.last_seen = Time.current
|
||||
issue.status = :open
|
||||
end
|
||||
end
|
||||
|
||||
def self.generate_fingerprint(payload)
|
||||
# Use Sentry's fingerprint if provided
|
||||
if payload["fingerprint"].present?
|
||||
payload["fingerprint"].join("::")
|
||||
else
|
||||
# Generate from exception type + location
|
||||
type = payload.dig("exception", "values", 0, "type")
|
||||
file = payload.dig("exception", "values", 0, "stacktrace", "frames", -1, "filename")
|
||||
line = payload.dig("exception", "values", 0, "stacktrace", "frames", -1, "lineno")
|
||||
|
||||
# Fallback to message if no exception
|
||||
if type.blank?
|
||||
message = payload["message"] || "Unknown Error"
|
||||
Digest::MD5.hexdigest(message)
|
||||
else
|
||||
"#{type}::#{file}::#{line}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.extract_title(payload)
|
||||
payload.dig("exception", "values", 0, "value") ||
|
||||
payload["message"] ||
|
||||
payload.dig("exception", "values", 0, "type") ||
|
||||
"Unknown Error"
|
||||
end
|
||||
|
||||
def self.extract_exception_type(payload)
|
||||
payload.dig("exception", "values", 0, "type")
|
||||
end
|
||||
|
||||
def record_event!(timestamp: Time.current)
|
||||
update!(
|
||||
count: count + 1,
|
||||
last_seen: timestamp
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def notify_new_issue
|
||||
IssueMailer.new_issue(self).deliver_later
|
||||
end
|
||||
|
||||
def notify_issue_reopened
|
||||
IssueMailer.issue_reopened(self).deliver_later
|
||||
end
|
||||
|
||||
def should_notify_new_issue?
|
||||
# Only notify for new issues in production environment or if explicitly enabled
|
||||
Rails.env.production? || ENV['SPLAT_EMAIL_NOTIFICATIONS'] == 'true'
|
||||
end
|
||||
|
||||
def was_reopened?
|
||||
# Check if status changed from resolved to open
|
||||
saved_change_to_status?(from: 1, to: 0) # resolved=1, open=0
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user