From 89a67770e66d11740948e90a41db6cee0482cf8e Mon Sep 17 00:00:00 2001 From: Patrick J Cherry Date: Wed, 13 Apr 2011 17:03:16 +0100 Subject: new version. --- lib/mauve/web_interface.rb | 334 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 lib/mauve/web_interface.rb (limited to 'lib/mauve/web_interface.rb') diff --git a/lib/mauve/web_interface.rb b/lib/mauve/web_interface.rb new file mode 100644 index 0000000..4569cb6 --- /dev/null +++ b/lib/mauve/web_interface.rb @@ -0,0 +1,334 @@ +# encoding: UTF-8 +require 'sinatra/base' +require 'sinatra-partials' +require 'haml' +require 'rack' +require 'rack-flash' + +if !defined?(JRUBY_VERSION) + require 'thin' +end + +module Mauve + # Our Sinatra app proper + # + class WebInterface < Sinatra::Base + + class PleaseAuthenticate < Exception; end + + use Rack::Session::Cookie, :expire_after => 604800 # 7 days in seconds + + enable :sessions + + use Rack::Flash + + set :root, "/usr/share/mauve" + set :views, "#{root}/views" + set :public, "#{root}/static" + set :static, true + set :show_exceptions, true + + logger = Log4r::Logger.new("Mauve::WebInterface") + + set :logging, true + set :logger, logger + set :dump_errors, true # ...will dump errors to the log + set :raise_errors, false # ...will not let exceptions out to main program + set :show_exceptions, false # ...will not show exceptions + + ######################################################################## + + before do + @person = Configuration.current.people[session['username']] + @title = "Mauve alert panel" + end + + get '/' do + redirect '/alerts' + end + + ######################################################################## + + ## Checks the identity of the person via a password. + # + # The password can be either the SSO or a local one defined + # in the configuration file. + # + post '/login' do + usr = params['username'] + pwd = params['password'] + ret_sso = helper_auth_SSO(usr, pwd) + ret_loc = helper_auth_local(usr, pwd) + if "success" == ret_sso or "success" == ret_loc + session['username'] = usr + else + flash['error'] =<<__MSG +

+ACCESS DENIED
+#{ret_sso}
+#{ret_loc}
+__MSG + end + redirect '/alerts' + end + + get '/logout' do + session.delete('username') + redirect '/alerts' + end + + get '/alerts' do + #now = MauveTime.now.to_f + please_authenticate() + find_active_alerts() + #pp MauveTime.now.to_f - now + haml(:alerts2) + end + + get '/_alert_summary' do + find_active_alerts; partial("alert_summary") + end + + get '/_alert_counts' do + find_active_alerts; partial("alert_counts") + end + + get '/_head' do + find_active_alerts() + partial("head") + end + + get '/alert/:id/detail' do + please_authenticate + + content_type("text/html") # I think + Alert.get(params[:id]).detail + end + + get '/alert/:id' do + please_authenticate + find_active_alerts + @alert = Alert.get(params['id']) + haml :alert + end + + post '/alert/:id/acknowledge' do + please_authenticate + + alert = Alert.get(params[:id]) + if alert.acknowledged? + alert.unacknowledge! + else + alert.acknowledge!(@person, 0) + end + content_type("application/json") + alert.to_json + end + + # Note that :until must be in seconds. + post '/alert/acknowledge/:id/:until' do + #now = MauveTime.now.to_f + please_authenticate + + alert = Alert.get(params[:id]) + alert.acknowledge!(@person, params[:until].to_i()) + + #print "Acknowledge request was processed in #{MauveTime.now.to_f - now} seconds\n" + content_type("application/json") + alert.to_json + end + + post '/alert/:id/raise' do + #now = MauveTime.now.to_f + please_authenticate + + alert = Alert.get(params[:id]) + alert.raise! + #print "Raise request was processed in #{MauveTime.now.to_f - now} seconds\n" + content_type("application/json") + alert.to_json + end + + post '/alert/:id/clear' do + please_authenticate + + alert = Alert.get(params[:id]) + alert.clear! + content_type("application/json") + alert.to_json + end + + post '/alert/:id/toggleDetailView' do + please_authenticate + + alert = Alert.get(params[:id]) + if nil != alert + id = params[:id].to_i() + session[:display_alerts][id] = (true == session[:display_alerts][id])? false : true + content_type("application/json") + 'all is good'.to_json + end + end + + post '/alert/fold/:subject' do + please_authenticate + + session[:display_folding][params[:subject]] = (true == session[:display_folding][params[:subject]])? false : true + content_type("application/json") + 'all is good'.to_json + end + + ######################################################################## + + get '/preferences' do + please_authenticate + find_active_alerts + haml :preferences + end + + ######################################################################## + + get '/events' do + please_authenticate + find_active_alerts + find_recent_alerts + haml :events + end + + ######################################################################## + + helpers do + include Sinatra::Partials + + def please_authenticate + raise PleaseAuthenticate.new unless @person + end + + def find_active_alerts + + # FIXME: make sure alerts only appear once some better way + #@urgent = AlertGroup.all_alerts_by_level(:urgent) + #@normal = AlertGroup.all_alerts_by_level(:normal) - @urgent + #@low = AlertGroup.all_alerts_by_level(:low) - @normal - @urgent + ook = Alert.get_all() + @urgent = ook[:urgent] + @normal = ook[:normal] + @low = ook[:low] + + # Get groups of alerts and count those acknowledged. + @grouped_ack_urgent = Hash.new() + @grouped_ack_normal = Hash.new() + @grouped_ack_low = Hash.new() + @grouped_new_urgent = Hash.new() + @grouped_new_normal = Hash.new() + @grouped_new_low = Hash.new() + @count_ack = Hash.new() + @count_ack[:urgent] = self.group_alerts(@grouped_ack_urgent, + @grouped_new_urgent, + @urgent) + @count_ack[:normal] = self.group_alerts(@grouped_ack_normal, + @grouped_new_normal, + @normal) + @count_ack[:low] = self.group_alerts(@grouped_ack_low, + @grouped_new_low, + @low) + @grouped_ack = Hash.new() + @grouped_new = Hash.new() + @grouped_ack_urgent.each_pair {|k,v| @grouped_ack[k] = v} + @grouped_ack_normal.each_pair {|k,v| @grouped_ack[k] = v} + @grouped_ack_low.each_pair {|k,v| @grouped_ack[k] = v} + @grouped_new_urgent.each_pair {|k,v| @grouped_new[k] = v} + @grouped_new_normal.each_pair {|k,v| @grouped_new[k] = v} + @grouped_new_low.each_pair {|k,v| @grouped_new[k] = v} + end + + ## Fill two hashs with alerts that are acknowledged or not. + # @param [Hash] ack Acknowledge hash. + # @param [Hash] new Unacknowledged (aka new) hash. + # @param [List] list List of alerts. + # @return [Fixnum] The count of acknowledged alerts. + def group_alerts(ack, new, list) + count = 0 + list.each do |alert| + #key = alert.source + '::' + alert.subject + key = alert.subject + if true == alert.acknowledged? + count += 1 + ack[key] = Array.new() if false == ack.has_key?(key) + ack[key] << alert + else + new[key] = Array.new() if false == new.has_key?(key) + new[key] << alert + end + if false == session[:display_alerts].has_key?(alert.id) + session[:display_alerts][alert.id] = false + end + if false == session[:display_folding].has_key?(key) + session[:display_folding][key] = false + end + #session[:display_alerts][alert.id] = true if false == session[:display_alerts].has_key?(alert.id) + #session[:display_folding][key] = true if false == session[:display_folding].has_key?(key) + new.each_key {|k| new[k].sort!{|a,b| a.summary <=> b.summary} } + ack.each_key {|k| ack[k].sort!{|a,b| a.summary <=> b.summary} } + end + return count + end + + def find_recent_alerts + since = params['since'] ? MauveTime.parse(params['since']) : (MauveTime.now-86400) + @alerts = Alert.all(:updated_at.gt => since, :order => [:raised_at.desc, :cleared_at.desc, :acknowledged_at.desc, :updated_at.desc, ]) + end + + def cycle(*list) + @cycle ||= 0 + @cycle = (@cycle + 1) % list.length + list[@cycle] + end + + ## Test for authentication with SSO. + # + def helper_auth_SSO (usr, pwd) + auth = AuthSourceBytemark.new() + begin + return "success" if true == auth.authenticate(usr,pwd) + return "SSO did not regcognise your login/password combination." + rescue ArgumentError => ex + return "SSO argument error: #{ex.message}" + rescue => ex + return "SSO generic error: #{ex.message}" + end + end + + ## Test for authentication with configuration file parameter. + # + def helper_auth_local (usr, pwd) + person = Configuration.current.people[params['username']] + return "I did not recognise your local login details." if !person + return "I did not recognise your local password." if Digest::SHA1.hexdigest(params['password']) != person.password + return "success" + end + + end + + ######################################################################## + + error PleaseAuthenticate do + status 403 + session[:display_alerts] = Hash.new() + session[:display_folding] = Hash.new() + haml :please_authenticate + end + + ######################################################################## + # @see http://stackoverflow.com/questions/2239240/use-rackcommonlogger-in-sinatra + def call(env) + if true == @logger.nil? + @logger = Log4r::Logger.new("mauve::Rack") + end + env['rack.errors'] = RackErrorsProxy.new(@logger) + super(env) + end + + end + +end -- cgit v1.2.1