Skip to content
Browse files

Add Hoptoad Widget, list app names with the error count

  • Loading branch information...
1 parent 054c6e3 commit ce749c401ad6d64dec6c5b6891ab3f671a3ef2c1 Marc Lagrange committed with
View
2 Gemfile
@@ -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
View
6 Gemfile.lock
@@ -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)
@@ -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)
@@ -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)
View
6 example/config.yml.example
@@ -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
View
29 widgets/hoptoad/hoptoad.css
@@ -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;
+}
View
54 widgets/hoptoad/hoptoad.js
@@ -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' }));
+ }
+});
+
View
116 widgets/hoptoad/hoptoad.rb
@@ -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
View
BIN widgets/hoptoad/images/hoptoad-promo.png
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 ce749c4

Please sign in to comment.
Something went wrong with that request. Please try again.