aboutsummaryrefslogtreecommitdiff
path: root/lib/mauve/history.rb
blob: 5a0caff96fe73dc8b00f1200792c3a5a7db5563f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# encoding: UTF-8
require 'mauve/datamapper'
require 'mauve/alert'
require 'log4r'

module Mauve
  class AlertHistory
    include DataMapper::Resource

    property :alert_id,   Integer, :key => true
    property :history_id, Integer, :key => true

    belongs_to :alert
    belongs_to :history

    after :destroy, :remove_unreferenced_histories

    def self.migrate!
      #
      # This copies the alert IDs from the old History table to the new AlertHistories thing, but only if there are no AertHistories 
      # and some Histories
      #
      if AlertHistory.last.nil? and not History.last.nil?
        # 
        # This is horrid. FIXME!
        #
        history_schema = '"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "type" VARCHAR(50) DEFAULT \'unknown\' NOT NULL, "event" TEXT DEFAULT \'Nothing set\' NOT NULL, "created_at" TIMESTAMP NOT NULL'
        history_cols   = 'id, type, event, created_at'
        ##
        # Now adjust the Histories table to remove its alert_id col
        #
        ["BEGIN TRANSACTION;",
        "INSERT INTO mauve_alert_histories (alert_id, history_id) SELECT alert_id, id FROM mauve_histories;",
        "CREATE TEMPORARY TABLE mauve_histories_backup( #{history_schema} );",
        "INSERT INTO mauve_histories_backup SELECT #{history_cols} FROM mauve_histories;",
        "DROP TABLE mauve_histories;",
        "CREATE TABLE mauve_histories( #{history_schema} );",
        "INSERT INTO mauve_histories SELECT #{history_cols} FROM mauve_histories_backup;",
        "DROP TABLE mauve_histories_backup;",
        "COMMIT;"].each do |statement|
          repository(:default).adapter.execute(statement)
        end
      end
    end

    private

    def remove_unreferenced_histories
      self.history.destroy unless self.history.alerts.count > 0
    end

  end

  class History
    include DataMapper::Resource
    
    # so .first always returns the most recent update
    default_scope(:default).update(:order => [:created_at.desc, :id.desc])
   
    #
    # If these properties change.. then the migration above will break horribly. FIXME.
    #
    property :id, Serial
    property :type,  String, :required => true, :default => "unknown", :lazy => false
    property :event, Text, :required => true, :default => "Nothing set", :lazy => false
    property :created_at, Time, :required => true

    has n, :alerts, :through => :alerthistory

    before :valid?, :set_created_at
    before :save,  :do_sanitize_html

    protected

    #
    # This cleans the HTML before saving.
    #
    def do_sanitize_html  
      html_permitted_in = [:event]

      attributes.each do |key, val|
        next if html_permitted_in.include?(key)
        next unless val.is_a?(String)

        attribute_set(key, Alert.remove_html(val))
      end

      html_permitted_in.each do |key|
        val = attribute_get(key)
        next unless val.is_a?(String)
        attribute_set(key, Alert.clean_html(val))
      end
    end


    def set_created_at(context = :default)
      self.created_at = Time.now unless self.created_at.is_a?(Time) 
    end

    public

    #
    # Blasted datamapper not eager-loading my model.
    #
    def add_to_cached_alerts(a)
      @cached_alerts ||= []
      if a.is_a?(Array) and a.all?{|m| m.is_a?(Alert)}
        @cached_alerts += a
      elsif a.is_a?(Alert)
        @cached_alerts << a
      else
        raise ArgumentError, "#{a.inspect} not an Alert"
      end
    end

    def alerts
      @cached_alerts ||= super
    end

    def reload
      @cached_alerts = nil
      super
    end

    def logger
      Log4r::Logger.new self.class.to_s
    end

  end

end