aboutsummaryrefslogtreecommitdiff
path: root/lib/mauve/history.rb
blob: fa5078d7e29f980d622d74becf2fec8e33a0474b (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
133
134
135
136
137
# encoding: UTF-8
require 'mauve/datamapper'
require 'mauve/alert'
require 'log4r'

module Mauve
  # This is the look-up table for Alerts and History to allow one History to
  # have many Alerts and vice-versa
  #
  #
  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

    # This is a horid migration to allow a move from an older version of Mauve
    # without this table.
    #
    #
    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, "user" VARCHAR(50) DEFAULT NULL, "created_at" TIMESTAMP NOT NULL'
        history_cols   = 'id, type, event, user, 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

    # This just removes histories that this AlertHistory used to refer to, if
    # they have no other alerts associated with them
    #
    #
    def remove_unreferenced_histories
      self.history.destroy unless self.history.alerts.count > 0
    end

  end

  # This class keeps a history for Mauve.  One History can relate to zero or
  # more Alerts, allowing notes to be added.
  #
  #
  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 :user, String
    property :created_at, EpochTime, :required => true

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

    before :valid?, :do_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

    # Update the created_at time on the object
    #
    def do_set_created_at(context = :default)
      self.created_at = Time.now if self.new?
    end

    public

    def cached_alerts
      return @cached_alerts if defined? @cached_alerts
      @cached_alerts = []
    end

    def reload
      @cached_alerts = []
      super
    end

    # @return Log4r::Logger
    def logger
      Log4r::Logger.new self.class.to_s
    end

  end

end