aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick J Cherry <patrick@bytemark.co.uk>2011-08-24 12:26:56 +0100
committerPatrick J Cherry <patrick@bytemark.co.uk>2011-08-24 12:26:56 +0100
commit71f395243d5cb7e2de918908f5c80b4ece37f58f (patch)
tree543d7928e830c1d8d765be4512f2afd81fed72c1
parent1a636d2c97368bc4c4019f4ddcff991ec5eccbce (diff)
Added XMPP interface. Fixes #1301
Also tidied calendar a bit
-rw-r--r--debian/changelog6
-rw-r--r--lib/mauve/alert.rb28
-rw-r--r--lib/mauve/notifiers/templates/xmpp.txt.erb8
-rw-r--r--lib/mauve/notifiers/xmpp.rb149
-rw-r--r--lib/mauve/version.rb2
-rw-r--r--lib/mauve/web_interface.rb40
-rw-r--r--views/_events_calendar_day.haml4
-rw-r--r--views/alert.haml5
-rw-r--r--views/events_list.haml23
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}
- &larr; Previous day
- = @start.strftime("%Y-%m-%d")
- %a{:href => "/events/list/#{(@start+1.day+10).strftime("%Y-%m-%d")}?"+request.query_string}
- Next day &rarr;
- |
- %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}
+ &larr; Previous day
+ = @start.strftime("%F")
+ %a{:href => "/events/list/#{(@start+1.day+1.hour).strftime("%F")}?"+request.query_string}
+ Next day &rarr;
+ |
+ %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.