Skip to content

Commit

Permalink
Add Hoptoad Widget, list app names with the error count
Browse files Browse the repository at this point in the history
  • Loading branch information
Marc Lagrange authored and pusewicz committed Apr 12, 2011
1 parent 8d0e134 commit a45e767
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ group :production do
gem "thin", "1.2.7"
gem "sinatra", "1.1.2"
gem "haml", "3.0.25"
gem "i18n"
gem "roxml"
end

group :test do
Expand Down
6 changes: 6 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ GEM
gemcutter (0.6.1)
git (1.2.5)
haml (3.0.25)
i18n (0.5.0)
jeweler (1.4.0)
gemcutter (>= 0.1.0)
git (>= 1.2.5)
Expand All @@ -29,6 +30,9 @@ GEM
rack (1.2.1)
rake (0.8.7)
roauth (0.0.3)
roxml (3.1.6)
activesupport (>= 2.3.0)
nokogiri (>= 1.3.3)
rspec (1.3.0)
rubyforge (2.0.4)
json_pure (>= 1.1.7)
Expand Down Expand Up @@ -57,10 +61,12 @@ DEPENDENCIES
eventmachine (= 0.12.10)
gemcutter
haml (= 3.0.25)
i18n
jeweler
launchy (= 0.3.7)
nokogiri (= 1.4.4)
rake (= 0.8.7)
roxml
rspec
sinatra (= 1.1.2)
thin (= 1.2.7)
Expand Down
6 changes: 6 additions & 0 deletions example/config.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,9 @@ widgets:
url: "http://www.engadget.com/rss.xml" # URL to RSS feed
xpath: "//item//title" # XPath to content to show
nitems: 5 # Number of RSS items to show

Hoptoad:
title: Apps errors
name: hoptoad
account: foo
auth_key: foobarbaz
29 changes: 29 additions & 0 deletions widgets/hoptoad/hoptoad.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* Hoptoad */

div.hoptoad { width: 330px; }
div.hoptoad .content img {
width: 32px;
height: 32px;
}

div.hoptoad span.app_name {
font-size: 14pt;
padding-left: 1em;
}

div.hoptoad span.no_app_errors {
font-weight: bold;
color: green;
padding-left: 10em;
font-size: 14pt;
}
div.hoptoad span.app_errors {
color: red;
font-weight: bold;
padding-left: 10em;
font-size: 14pt;
}

div.hoptoad .content p {
line-height: 24px;
}
54 changes: 54 additions & 0 deletions widgets/hoptoad/hoptoad.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
var Hoptoad = Class.create(Widget, {
initialize: function($super, widget_id, config) {
this.messages = [];
return($super(widget_id, config));
},

handlePayload: function(payload) {
this.messages = payload;
},

build: function() {
this.contentContainer = this.buildContent();
this.headerContainer = this.buildHeader();
this.iconContainer = this.buildIcon();

this.container.insert(this.headerContainer);
this.container.insert(this.iconContainer);
this.container.insert(this.contentContainer);

this.makeDraggable();
},

update: function() {
this.contentContainer.childElements().invoke('remove');

this.messages.reverse(false).each(function(message) {
var cont = new Element('p');
if (message.errors == "0") {
var class_errors = "no_app_errors";
} else {
var class_errors = "app_errors";
}
var app_errors = new Element('div', { className: 'app_errors' }).update(
'<span class="app_name">' + message.name + '</span>: <span class="' + class_errors + '">' + message.errors + '</span>'
);
cont.insert(app_errors);
cont.insert(new Element('hr' ));
this.contentContainer.insert(cont);
}.bind(this));
},

buildContent: function() {
return(new Element("div", { 'class': 'content' }));
},

buildHeader: function() {
return(new Element("h2", { 'class': 'handle' }).update(this.title));
},

buildIcon: function() {
return(new Element("img", { src: "images/hoptoad/hoptoad-promo.png", 'class': 'hoptoad icon' }));
}
});

116 changes: 116 additions & 0 deletions widgets/hoptoad/hoptoad.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
require 'roxml'
module Sonia
module Widgets
# ROXML classes doesn't include all stuff that Hoptoad returns
# since we dont need it : we already have the api key and we
# only need to count the total of errors for each projects
# ROXML Projects class
class Project
include ROXML
xml_accessor :id
xml_accessor :name
end
class Projects
include ROXML
xml_accessor :projects, :as => [Project]
end

# ROXML Errors class
class Group
include ROXML
xml_accessor :project_id, :from => "@project-id"
xml_accessor :resolved
end

class Groups
include ROXML
xml_accessor :groups, :as => [Group]
end

class Hoptoad < Sonia::Widget
PROJECTS_URL = "http://%s.hoptoadapp.com/projects.xml?auth_token=%s" # SSL redirecto to non-ssl url
PROJECT_ERRORS_URL = "http://%s.hoptoadapp.com/errors.xml?auth_token=%s&project_id=%s" # same

def initialize(config)
super(config)

@projects = []
EventMachine::add_periodic_timer(60 * 5) { fetch_data }
end

def initial_push
fetch_data
end

private
def fetch_data
fetch_projects do
fetch_errors
end
end

def fetch_projects(&blk)
log_info "Polling `#{projects_url}'"
http = EventMachine::HttpRequest.new(projects_url).get
http.errback { log_fatal_error(http) }
http.callback {
handle_projects_response(http)
blk.call
}
end

def handle_projects_response(http)
if http.response_header.status == 200
@projects = Projects.from_xml(http.response).projects.map { |p| { :id => p.id, :name => p.name } }
else
log_unsuccessful_response_body(http.response)
end
rescue => e
log_backtrace(e)
end

def fetch_errors
multi = EventMachine::MultiRequest.new
@projects.each do |project|
url = project_errors_url(project[:id])
log_info "Polling `#{url}'"
multi.add(EventMachine::HttpRequest.new(url).get)
end
multi.errback { log_fatal_error(multi) }
multi.callback {
handle_errors_response(multi)
}
end

def handle_errors_response(multi)
errors = multi.responses[:succeeded].map do |response|
begin
error_p_id = response.instance_variable_get(:@uri).query.split("project_id=").last
project = project(error_p_id)
project[:errors] = Groups.from_xml(response.response).groups.size
project
rescue => e
log_backtrace(e)
end
end

push errors
rescue => e
log_backtrace(e)
end


def projects_url
PROJECTS_URL % [config.account, config.auth_key]
end
def project_errors_url(project_id)
PROJECT_ERRORS_URL % [config.account, config.auth_key, project_id]
end

def project(project_id)
@projects.detect { |r| r[:id] == project_id }
end

end
end
end
Binary file added widgets/hoptoad/images/hoptoad-promo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit a45e767

Please sign in to comment.