split the report into lines
[opensuse:apport-opensuse-crashdb.git] / app / models / report.rb
1 require 'md5'
2 require 'crash_log'
3
4 class Report < ActiveRecord::Base
5   #acts_as_versioned :extend => ReportAggregations
6   has_many :report_lines
7
8   # Extended Mandatory Keys: Title, ExecutableBuildId, Stacktrace
9   MANDATORY_KEYS = %w(ProblemType Date Uname Title ExecutableBuildId Stacktrace)
10   FORBIDDEN_KEYS = %w(UnreportableReason)
11
12   validate :validate_crash_log_format
13   validate :validate_ignore
14
15   before_create :generate_uuid
16   validates_uniqueness_of :uuid
17
18   def ignored?
19     @ignored
20   end
21
22   def invalid?
23     @invalid
24   end
25
26   def versions
27     # need to find out what versions are good for
28     return [0]
29   end
30
31   def self.find_reports(*args)
32     with_scope :find => { :conditions => [ 'uuid != ?', "0"*32 ] } do
33       find(*args)
34     end
35   end
36
37   def get(key)
38     line = report_lines.find(:first, :conditions => { :rkey => key })
39     return line.value if line
40     return nil
41   end
42
43   def sorted_keys
44     keys = []
45     report_lines.find(:all, :order => :position).each do |l|
46       keys << l.rkey
47     end
48     logger.debug "keys #{keys.inspect}"
49     return keys
50   end
51
52   private
53   def generate_uuid
54     # generate uuid
55     self.uuid = MD5.hexdigest(self.content.log_text)
56     logger.info "LOG: uuid is #{self.uuid}"
57   end
58
59   def validate_crash_log_format
60     logger.debug "validating crash log format"
61     set_keys = self.content.keys & MANDATORY_KEYS
62     unless (MANDATORY_KEYS - set_keys).empty?
63       errors.add_to_base "missing crash log keys: #{(MANDATORY_KEYS - set_keys).join(", ")}"
64       @invalid = true
65     end
66     set_keys = self.content.keys & FORBIDDEN_KEYS
67     if not set_keys.empty?
68       errors.add_to_base "forbidden crash log keys: #{set_keys.join(", ")}"
69       @invalid = true
70     end
71   rescue CrashLog::ParseError => e
72     errors.add_to_base "crash log parsing failed: #{e.message}"
73     @invalid = true
74   end
75
76   def validate_ignore
77     if self.content && self.content['Ignore'] =~ /[Tt]rue/
78       @ignored = true
79       logger.info "Ignore: true, skipping save"
80       errors.add_to_base "log contains ignore line, skipping save"
81     end
82   end
83
84   def version_condition_met?
85     !invalid? and !ignored?
86   end
87 end