diff options
-rw-r--r-- | debian/changelog | 6 | ||||
-rw-r--r-- | lib/mauve/alert.rb | 28 | ||||
-rw-r--r-- | lib/mauve/notifiers/templates/xmpp.txt.erb | 8 | ||||
-rw-r--r-- | lib/mauve/notifiers/xmpp.rb | 149 | ||||
-rw-r--r-- | lib/mauve/version.rb | 2 | ||||
-rw-r--r-- | lib/mauve/web_interface.rb | 40 | ||||
-rw-r--r-- | views/_events_calendar_day.haml | 4 | ||||
-rw-r--r-- | views/alert.haml | 5 | ||||
-rw-r--r-- | views/events_list.haml | 23 |
9 files changed, 233 insertions, 32 deletions
diff --git a/debian/changelog b/debian/changelog index 184cb6c..b7d2a38 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +mauvealert (3.5.0) stable; urgency=low + + * Added XMPP interface + + -- Patrick J Cherry <patrick@bytemark.co.uk> Wed, 24 Aug 2011 12:24:55 +0100 + mauvealert (3.4.4) stable; urgency=low * Added events calendar diff --git a/lib/mauve/alert.rb b/lib/mauve/alert.rb index 75aa35e..752a132 100644 --- a/lib/mauve/alert.rb +++ b/lib/mauve/alert.rb @@ -260,7 +260,12 @@ module Mauve self.will_unacknowledge_at = ack_until self.update_type = "acknowledged" - logger.error("Couldn't save #{self}") unless save + unless save + logger.error("Couldn't save #{self}") + false + else + true + end end def unacknowledge! @@ -269,7 +274,12 @@ module Mauve self.will_unacknowledge_at = nil self.update_type = (raised? ? "raised" : "cleared") - logger.error("Couldn't save #{self}") unless save + unless save + logger.error("Couldn't save #{self}") + false + else + true + end end def raise!(at = Time.now) @@ -303,7 +313,12 @@ module Mauve self.update_type = "raised" if self.update_type.nil? or self.update_type != "changed" or self.original_attributes[Alert.properties[:update_type]] == "cleared" end - logger.error("Couldn't save #{self}") unless save + unless save + logger.error("Couldn't save #{self}") + false + else + true + end end def clear!(at = Time.now) @@ -329,7 +344,12 @@ module Mauve self.update_type = "cleared" end - logger.error("Couldn't save #{self}") unless save + unless save + logger.error("Couldn't save #{self}") + false + else + true + end end # Returns the time at which a timer loop should call poll_event to either diff --git a/lib/mauve/notifiers/templates/xmpp.txt.erb b/lib/mauve/notifiers/templates/xmpp.txt.erb index a73f41f..57f16f4 100644 --- a/lib/mauve/notifiers/templates/xmpp.txt.erb +++ b/lib/mauve/notifiers/templates/xmpp.txt.erb @@ -12,9 +12,11 @@ if alert.source != alert.subject %> -- from <%= alert.source %><% end %>. <%=WebInterface.url_for(alert)%><% -if was_suppressed and not is_suppressed +if defined? was_suppressed and defined? is_suppressed + if was_suppressed and not is_suppressed %> (Normal service has resumed.)<% -elsif is_suppressed and not was_suppressed + elsif is_suppressed and not was_suppressed %> (Further alerts suppressed until things calm down.)<% -end + end +end %> diff --git a/lib/mauve/notifiers/xmpp.rb b/lib/mauve/notifiers/xmpp.rb index 7cb71c4..0efed60 100644 --- a/lib/mauve/notifiers/xmpp.rb +++ b/lib/mauve/notifiers/xmpp.rb @@ -414,14 +414,15 @@ module Mauve # Received a message with a body. # jid = msg.from + logger.debug "Received #{msg.body} from #{jid}" end # # I don't have time to talk to myself! # if jid and jid.strip != @client.jid.strip - txt = File.executable?('/usr/games/fortune') ? `/usr/games/fortune -s -n 60`.chomp : "I'd love to stay and chat, but I'm really too busy." - send_message(jid, txt) + reply = parse_command(msg) + send_message(jid, reply) end end @@ -440,6 +441,138 @@ module Mauve end end + def parse_command(msg) + case msg.body + when /help/i + do_parse_help(msg) + when /show\s?/i + do_parse_show(msg) + when /ack/i + do_parse_ack(msg) + else + "Sorry. I don't understand. Try asking me for help" + end + end + + def do_parse_help(msg) + msg.body =~ /help\s+(\w+)/i + cmd = $1 + + return case cmd + when "show" + <<EOF +Show command: Lists all raised or acknowledged alerts, or the first or last few. +e.g. + show -- shows all raised alerts + show ack -- shows all acknowledged alerts + show first 10 acknowledged -- shows first 10 acknowledged + show last 5 raised -- shows last 5 raised alerts +EOF + when /^ack/ + <<EOF +Acknowledge command: Acknowledges one or more alerts for a set period of time. This can only be done from a "private" chat. +e.g. + ack 1 for 2 hours -- acknowledges alert no. 1 for 2 wall-clock hours + ack 1,2,3 for 2 working hours -- acknowledges alerts 1, 2, and 3 for 2 working hours +EOF + else + "I am Mauve #{Mauve::VERSION}. I understand \"help\", \"show\" and \"acknowledge\" commands. Try \"help show\"." + end + end + + def do_parse_show(msg) + return "Sorry -- I don't understand your show command." unless + msg.body =~ /show(?:\s+(first|last)\s+(\d+))?(?:\s+(events|raised|ack(?:d|nowledged)?))?/i + + first_or_last = $1 + n_items = ($2 || -1).to_i + + type = $3 || "raised" + type = "acknowledged" if type =~ /^ack/ + + msg = [] + + items = case type + when "acknowledged" + Alert.all_acknowledged + when "events" + History.all(:created_at.gte => Time.now - 24.hours) + else + Alert.all_raised + end + + if first_or_last == "first" + items = items.first(n_items) if n_items >= 0 + elsif first_or_last == "last" + items = items.last(n_items) if n_items >= 0 + end + + return "Nothing to show" if items.length == 0 + + template_file = File.join(File.dirname(__FILE__),"templates","xmpp.txt.erb") + if File.exists?(template_file) + template = File.read(template_file) + else + logger.error("Could not find xmpp.txt.erb template") + template = nil + end + + (["Alerts #{type}:"] + items.collect do |alert| + "#{alert.id}: " + ERB.new(template).result(binding).chomp + end).join("\n") + end + + def do_parse_ack(msg) + return "Sorry -- I don't understand your acknowledge command." unless + msg.body =~ /ack(?:nowledge)?\s+([\d,]+)\s+for\s+(\d+)\s+(work(?:ing)|day(?:time)|wall(?:-?clock))?\s*hours?/i + + alerts, n_hours, type_hours = [$1,$2, $3] + + alerts = alerts.split(",") + n_hours = n_hours.to_i + + type_hours = case type_hours + when /^wall/ + "wallclock" + when /^work/ + "working" + else + "daytime" + end + + ack_until = Time.now.in_x_hours(n_hours, type_hours) + username = get_username_for(msg.from) + + if is_muc?(Configuration.current.people[username].xmpp) + return "I'm sorry -- if you want to acknowledge alerts, please do it from a private chat" + end + + msg = [] + msg << "Acknowledgment results:" if alerts.length > 1 + + alerts.each do |alert_id| + alert = Alert.get(alert_id) + + if alert.nil? + msg << "#{alert_id}: alert not found" + next + end + + if alert.cleared? + msg << "#{alert_id}: alert already cleared" if alert.cleared? + next + end + + if alert.acknowledge!(Configuration.current.people[username], ack_until) + msg << "#{alert_id}: Acknowledged until #{ack_until.to_s_human}" + else + msg << "#{alert_id}: Acknowledgment failed." + end + end + + return msg.join("\n") + end + def check_alert_conditions(destination, conditions) any_failed = conditions.keys.collect do |key| case key @@ -498,13 +631,21 @@ module Mauve results.include?(true) end - def is_known_contact?(jid) + # + # Returns the username of the jid, if any + # + def get_username_for(jid) jid = JID.new(jid) unless jid.is_a?(JID) - Configuration.current.people.any? do |username, person| + ans = Configuration.current.people.find do |username, person| next unless person.xmpp.is_a?(JID) person.xmpp.strip == jid.strip end + ans.nil? ? ans : ans.first + end + + def is_known_contact?(jid) + !get_username_for(jid).nil? end end diff --git a/lib/mauve/version.rb b/lib/mauve/version.rb index 7571fea..db20823 100644 --- a/lib/mauve/version.rb +++ b/lib/mauve/version.rb @@ -1,5 +1,5 @@ module Mauve - VERSION="3.4.4" + VERSION="3.5.0" end diff --git a/lib/mauve/web_interface.rb b/lib/mauve/web_interface.rb index 386dfac..fdf2ddb 100644 --- a/lib/mauve/web_interface.rb +++ b/lib/mauve/web_interface.rb @@ -193,7 +193,7 @@ EOF # ack_until is in milliseconds! ack_until = params[:ack_until] n_hours = params[:n_hours] || 2 - type_hours = params[:type_hours] || "daylight" + type_hours = params[:type_hours] || "daytime" alerts = params[:alerts] || [] note = params[:note] || nil @@ -327,6 +327,7 @@ EOF get '/alert/:id' do find_active_alerts @alert = Alert.get!(params['id']) + haml :alert end @@ -395,10 +396,16 @@ EOF ######################################################################## - - get '/events/alert/:id' do + query = {:alert => {}, :history => {}} + query[:alert][:id] = params[:id] + + query[:history][:type] = ["update", "notification"] + + @alert = Alert.get!(params['id']) + @events = find_events(query) + haml :events_list end get '/events/calendar' do @@ -465,16 +472,37 @@ EOF get '/events/list/:start' do if params[:start] =~ /\A(\d{4,4})-(\d{1,2})-(\d{1,2})\Z/ - @start = Time.local($1.to_i,$2.to_i,$3.to_i,0,0,0,0) + start = Time.local($1.to_i,$2.to_i,$3.to_i,0,0,0,0) else t = Time.now + start = Time.local(t.year, t.month, t.day, 0,0,0,0) + end + + finish = start + 1.day + 1.hour + + redirect "/events/list/#{start.strftime("%Y-%m-%d")}/#{finish.strftime("%Y-%m-%d")}" + end + + get '/events/list/:start/:finish' do + + t = Time.now + if params[:start] =~ /\A(\d{4,4})-(\d{1,2})-(\d{1,2})\Z/ + @start = Time.local($1.to_i,$2.to_i,$3.to_i,0,0,0,0) + else @start = Time.local(t.year, t.month, t.day, 0,0,0,0) end + if params[:finish] =~ /\A(\d{4,4})-(\d{1,2})-(\d{1,2})\Z/ + finish = Time.local($1.to_i,$2.to_i,$3.to_i,0,0,0,0) + else + t += 1.day + 1.hour + finish = Time.local(t.year, t.month, t.day, 0,0,0,0) + end + query = {:history => {}} query[:history][:created_at.gte] = @start - query[:history][:created_at.lt] = @start + 1.day - + query[:history][:created_at.lt] = finish + @events = find_events(query) haml :events_list diff --git a/views/_events_calendar_day.haml b/views/_events_calendar_day.haml index 9682b56..1b42520 100644 --- a/views/_events_calendar_day.haml +++ b/views/_events_calendar_day.haml @@ -1,6 +1,6 @@ %td{:class => (@today.month % 2 == 0 ? "even" : "odd")} %p.event_date - %a{:href => "/events/list/#{@today.strftime("%Y-%m-%d")}?#{request.query_string}"} + %a{:href => "/events/list/#{@today.strftime("%F")}?#{request.query_string}"} = @today.strftime(((@today - 1.day).month != @today.month) ? "%d %b" : "%d") =partial("history", :collection => events_calendar_day.first(10)) %p @@ -9,6 +9,6 @@ = events_calendar_day.length - 10 more events to display. - if events_calendar_day.length > 0 - %a{:href => "/events/list/#{@today.strftime("%Y-%m-%d")}?#{request.query_string}"} + %a{:href => "/events/list/#{@today.strftime("%F")}?#{request.query_string}"} Show the whole day. - @today += 1.day diff --git a/views/alert.haml b/views/alert.haml index 30aeb86..220f871 100644 --- a/views/alert.haml +++ b/views/alert.haml @@ -47,11 +47,14 @@ %th History %td %ul#histories - - @alert.histories.first(10).each do |history| + - @alert.histories.all(:created_at.gte => Time.now - 3.days).each do |history| %li = history.event at = (history.created_at.nil? ? "unkown" : history.created_at.to_s_human) + %p + %a{:href => "/events/alert/#{@alert.id}"} + View full event history %h2 Actions - if !@alert.acknowledged? %form{:method => :post, :action => "/alert/#{@alert.id}/acknowledge"} diff --git a/views/events_list.haml b/views/events_list.haml index 008b667..ff56310 100644 --- a/views/events_list.haml +++ b/views/events_list.haml @@ -1,18 +1,19 @@ %h2 Events List -%p - %a{:href => "/events/list/#{(@start-1.day-10).strftime("%Y-%m-%d")}?"+request.query_string} - ← Previous day - = @start.strftime("%Y-%m-%d") - %a{:href => "/events/list/#{(@start+1.day+10).strftime("%Y-%m-%d")}?"+request.query_string} - Next day → - | - %a{:href => "/events/calendar/#{@start.strftime("%Y-%m")}?"+request.query_string} - Calendar view -= partial('events_form') +- if @start + %p + %a{:href => "/events/list/#{(@start-1.day+1.hour).strftime("%F")}?"+request.query_string} + ← Previous day + = @start.strftime("%F") + %a{:href => "/events/list/#{(@start+1.day+1.hour).strftime("%F")}?"+request.query_string} + Next day → + | + %a{:href => "/events/calendar/#{@start.strftime("%Y-%m")}?"+request.query_string} + Calendar view + = partial('events_form') - if @events.length > 0 = partial('history', :collection => @events) - else %p %strong - No events for today. + No events. |