Skip to content
This repository
Browse code

Add Hoptoad Widget, list app names with the error count

  • Loading branch information...
commit ce749c401ad6d64dec6c5b6891ab3f671a3ef2c1 1 parent 054c6e3
authored pusewicz committed
2  Gemfile
@@ -14,6 +14,8 @@ group :production do
14 14
   gem "thin", "1.2.7"
15 15
   gem "sinatra", "1.1.2"
16 16
   gem "haml", "3.0.25"
  17
+  gem "i18n"
  18
+  gem "roxml"
17 19
 end
18 20
 
19 21
 group :test do
6  Gemfile.lock
@@ -17,6 +17,7 @@ GEM
17 17
     gemcutter (0.6.1)
18 18
     git (1.2.5)
19 19
     haml (3.0.25)
  20
+    i18n (0.5.0)
20 21
     jeweler (1.4.0)
21 22
       gemcutter (>= 0.1.0)
22 23
       git (>= 1.2.5)
@@ -29,6 +30,9 @@ GEM
29 30
     rack (1.2.1)
30 31
     rake (0.8.7)
31 32
     roauth (0.0.3)
  33
+    roxml (3.1.6)
  34
+      activesupport (>= 2.3.0)
  35
+      nokogiri (>= 1.3.3)
32 36
     rspec (1.3.0)
33 37
     rubyforge (2.0.4)
34 38
       json_pure (>= 1.1.7)
@@ -57,10 +61,12 @@ DEPENDENCIES
57 61
   eventmachine (= 0.12.10)
58 62
   gemcutter
59 63
   haml (= 3.0.25)
  64
+  i18n
60 65
   jeweler
61 66
   launchy (= 0.3.7)
62 67
   nokogiri (= 1.4.4)
63 68
   rake (= 0.8.7)
  69
+  roxml
64 70
   rspec
65 71
   sinatra (= 1.1.2)
66 72
   thin (= 1.2.7)
6  example/config.yml.example
@@ -65,3 +65,9 @@ widgets:
65 65
     url: "http://www.engadget.com/rss.xml" # URL to RSS feed
66 66
     xpath: "//item//title"                 # XPath to content to show
67 67
     nitems: 5                              # Number of RSS items to show
  68
+
  69
+  Hoptoad:
  70
+    title: Apps errors
  71
+    name: hoptoad
  72
+    account: foo
  73
+    auth_key: foobarbaz
29  widgets/hoptoad/hoptoad.css
... ...
@@ -0,0 +1,29 @@
  1
+/* Hoptoad */
  2
+
  3
+div.hoptoad { width: 330px; }
  4
+div.hoptoad .content img {
  5
+  width: 32px;
  6
+  height: 32px;
  7
+}
  8
+
  9
+div.hoptoad span.app_name {
  10
+    font-size: 14pt;
  11
+    padding-left: 1em;
  12
+}
  13
+
  14
+div.hoptoad span.no_app_errors {
  15
+    font-weight: bold;
  16
+    color: green;
  17
+    padding-left: 10em;
  18
+    font-size: 14pt;
  19
+}
  20
+div.hoptoad span.app_errors {
  21
+    color: red;
  22
+    font-weight: bold;
  23
+    padding-left: 10em;
  24
+    font-size: 14pt;
  25
+}
  26
+
  27
+div.hoptoad .content p {
  28
+  line-height: 24px;
  29
+}
54  widgets/hoptoad/hoptoad.js
... ...
@@ -0,0 +1,54 @@
  1
+var Hoptoad = Class.create(Widget, {
  2
+  initialize: function($super, widget_id, config) {
  3
+    this.messages = [];
  4
+    return($super(widget_id, config));
  5
+  },
  6
+
  7
+  handlePayload: function(payload) {
  8
+    this.messages = payload;
  9
+  },
  10
+
  11
+  build: function() {
  12
+    this.contentContainer = this.buildContent();
  13
+    this.headerContainer  = this.buildHeader();
  14
+    this.iconContainer    = this.buildIcon();
  15
+
  16
+    this.container.insert(this.headerContainer);
  17
+    this.container.insert(this.iconContainer);
  18
+    this.container.insert(this.contentContainer);
  19
+
  20
+    this.makeDraggable();
  21
+  },
  22
+
  23
+  update: function() {
  24
+    this.contentContainer.childElements().invoke('remove');
  25
+
  26
+    this.messages.reverse(false).each(function(message) {
  27
+      var cont = new Element('p');
  28
+      if (message.errors == "0") {
  29
+          var class_errors = "no_app_errors";
  30
+      } else {
  31
+          var class_errors = "app_errors";
  32
+      }
  33
+      var app_errors = new Element('div', { className: 'app_errors' }).update(
  34
+        '<span class="app_name">' + message.name + '</span>: <span class="' + class_errors + '">' + message.errors + '</span>'
  35
+      );
  36
+      cont.insert(app_errors);
  37
+      cont.insert(new Element('hr' ));
  38
+      this.contentContainer.insert(cont);
  39
+    }.bind(this));
  40
+  },
  41
+
  42
+  buildContent: function() {
  43
+    return(new Element("div", { 'class': 'content' }));
  44
+  },
  45
+
  46
+  buildHeader: function() {
  47
+    return(new Element("h2", { 'class': 'handle' }).update(this.title));
  48
+  },
  49
+
  50
+  buildIcon: function() {
  51
+    return(new Element("img", { src: "images/hoptoad/hoptoad-promo.png", 'class': 'hoptoad icon' }));
  52
+  }
  53
+});
  54
+
116  widgets/hoptoad/hoptoad.rb
... ...
@@ -0,0 +1,116 @@
  1
+require 'roxml'
  2
+module Sonia
  3
+  module Widgets
  4
+    # ROXML classes doesn't include all stuff that Hoptoad returns
  5
+    # since we dont need it : we already have the api key and we
  6
+    # only need to count the total of errors for each projects
  7
+    # ROXML Projects class
  8
+    class Project
  9
+      include ROXML
  10
+      xml_accessor :id
  11
+      xml_accessor :name
  12
+    end
  13
+    class Projects
  14
+      include ROXML
  15
+      xml_accessor :projects, :as => [Project]
  16
+    end
  17
+
  18
+    # ROXML Errors class
  19
+    class Group
  20
+      include ROXML
  21
+      xml_accessor :project_id, :from => "@project-id"
  22
+      xml_accessor :resolved
  23
+    end
  24
+
  25
+    class Groups
  26
+      include ROXML
  27
+      xml_accessor :groups, :as => [Group]
  28
+    end
  29
+
  30
+    class Hoptoad < Sonia::Widget
  31
+      PROJECTS_URL       = "http://%s.hoptoadapp.com/projects.xml?auth_token=%s" # SSL redirecto to non-ssl url
  32
+      PROJECT_ERRORS_URL = "http://%s.hoptoadapp.com/errors.xml?auth_token=%s&project_id=%s" # same
  33
+
  34
+      def initialize(config)
  35
+        super(config)
  36
+
  37
+        @projects = []
  38
+        EventMachine::add_periodic_timer(60 * 5) { fetch_data }
  39
+      end
  40
+
  41
+      def initial_push
  42
+        fetch_data
  43
+      end
  44
+
  45
+      private
  46
+      def fetch_data
  47
+        fetch_projects do
  48
+          fetch_errors
  49
+        end
  50
+      end
  51
+
  52
+      def fetch_projects(&blk)
  53
+        log_info "Polling `#{projects_url}'"
  54
+        http = EventMachine::HttpRequest.new(projects_url).get
  55
+        http.errback { log_fatal_error(http) }
  56
+        http.callback {
  57
+          handle_projects_response(http)
  58
+          blk.call
  59
+        }
  60
+      end
  61
+
  62
+      def handle_projects_response(http)
  63
+        if http.response_header.status == 200
  64
+          @projects = Projects.from_xml(http.response).projects.map { |p| { :id => p.id, :name => p.name } }
  65
+        else
  66
+          log_unsuccessful_response_body(http.response)
  67
+        end
  68
+      rescue => e
  69
+        log_backtrace(e)
  70
+      end
  71
+
  72
+      def fetch_errors
  73
+        multi = EventMachine::MultiRequest.new
  74
+        @projects.each do |project|
  75
+          url = project_errors_url(project[:id])
  76
+          log_info "Polling `#{url}'"
  77
+          multi.add(EventMachine::HttpRequest.new(url).get)
  78
+        end
  79
+        multi.errback { log_fatal_error(multi) }
  80
+        multi.callback {
  81
+          handle_errors_response(multi)
  82
+        }
  83
+      end
  84
+
  85
+      def handle_errors_response(multi)
  86
+        errors = multi.responses[:succeeded].map do |response|
  87
+          begin
  88
+            error_p_id = response.instance_variable_get(:@uri).query.split("project_id=").last
  89
+            project = project(error_p_id)
  90
+            project[:errors] = Groups.from_xml(response.response).groups.size
  91
+            project
  92
+          rescue => e
  93
+            log_backtrace(e)
  94
+          end
  95
+        end
  96
+
  97
+        push errors
  98
+      rescue => e
  99
+        log_backtrace(e)
  100
+      end
  101
+
  102
+
  103
+      def projects_url
  104
+        PROJECTS_URL % [config.account, config.auth_key]
  105
+      end
  106
+      def project_errors_url(project_id)
  107
+        PROJECT_ERRORS_URL % [config.account, config.auth_key, project_id]
  108
+      end
  109
+
  110
+      def project(project_id)
  111
+        @projects.detect { |r| r[:id] == project_id }
  112
+      end
  113
+
  114
+    end
  115
+  end
  116
+end
BIN  widgets/hoptoad/images/hoptoad-promo.png

0 notes on commit ce749c4

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