# encoding: UTF-8 require 'mauve/datamapper' require 'log4r' module Mauve # # Class to record changes to alerts. Also responsible for keeping records for reminders. # class AlertChanged include DataMapper::Resource # so .first always returns the most recent update default_scope(:default).update(:order => [:at.desc, :id.desc]) property :id, Serial property :alert_id, Integer, :required => true property :person, String, :required => true property :at, EpochTime, :required => true property :was_relevant, Boolean, :required => true, :default => true property :level, String, :required => true property :update_type, String, :required => true property :remind_at, EpochTime, :required => false belongs_to :alert before :valid?, :do_set_timestamps protected def do_set_timestamps(context = :default) self.at = Time.now unless self.original_attributes.has_key?("at") end public # @return [String] def to_s "#" end # @deprecated I don't think was_relevant is used any more. # def was_relevant=(value) attribute_set(:was_relevant, value) end # The time this object was last updated # # @return [Time] def updated_at self.at end # Set the time this object was last updated # # @param [Time] t # @return [Time] def updated_at=(t) self.at = t end # @return [Log4r::Logger] def logger Log4r::Logger.new self.class.to_s end # Sends a reminder about this alert state change, or forget about it if # the alert has been acknowledged # # @return [Boolean] indicating successful update of the AlertChanged object def remind unless alert.is_a?(Alert) logger.info "#{self.inspect} lost alert #{alert_id}. Killing self." destroy return false end if !alert_group logger.info("No alert group matches any more. Clearing reminder for #{self.alert}.") self.remind_at = nil return save end if alert.acknowledged? or alert.cleared? logger.info("Alert already acknowledged/cleared. Clearing reminder due for #{self.alert}.") self.remind_at = nil return save end # # Postpone reminders from previous runs, if needed. # if Server.instance.in_initial_sleep? and self.at < Server.instance.started_at self.remind_at = Server.instance.started_at + Server.instance.initial_sleep logger.info("Postponing reminder for #{self.alert} until #{self.remind_at} since this reminder was updated in a prior run of Mauve.") return save end # # Push this notifitcation onto the queue. # Server.notification_push([alert, Time.now]) # # Need to make sure this reminder is cleared. # self.remind_at = nil if self.save logger.debug "Successfully cleared #{self}" true else logger.warn "Failed to clear #{self} -- this will lead to duplicate reminders." false end end # The time this AlertChanged should next be polled at, or nil. Mimics # interaface from Alert. # # @return [Time, NilClass] def due_at remind_at ? remind_at : nil end # Sends a reminder, if needed. Mimics interaface from Alert. # # @return [Boolean] showing polling was successful def poll # mimic interface from Alert logger.debug("Polling #{self.to_s}") if remind_at.is_a?(Time) and remind_at <= Time.now remind else true end end # The AlertGroup for this object # # @return [Mauve::AlertGroup] def alert_group alert.alert_group end class << self # Finds the next reminder due, or nil if nothing due. # # @return [Mauve::AlertChanged, NilClass] def next_reminder first(:remind_at.not => nil, :order => [:remind_at]) end # Finds the next event due. Mimics interface from Alert. # # @return [Mauve::AlertChanged, NilClass] def find_next_with_event next_reminder end # @deprecated I don't think this is used any more. # # @return [Array] def all_overdue(at = Time.now) all(:remind_at.not => nil, :remind_at.lt => at, :order => [:remind_at]).to_a end end end end