Commit f5825ed2f8e14a938443dc7004317caaf58c092b

Authored by Marcin Ciunelis
2 parents 33abb5b8 fb70eaa0
Exists in master and in 1 other branch production

Merge branch 'master' into api-2.3

Gemfile
1 1 source 'http://rubygems.org'
2 2  
3   -gem 'rails', '3.2.6'
  3 +gem 'rails', '3.2.8'
4 4  
5 5 gem 'nokogiri'
6 6 gem 'mongoid', '~> 2.4.10'
... ... @@ -49,6 +49,7 @@ group :development, :test do
49 49 end
50 50 # gem 'rpm_contrib'
51 51 # gem 'newrelic_rpm'
  52 + gem 'capistrano'
52 53 end
53 54  
54 55 group :test do
... ...
Gemfile.lock
... ... @@ -2,35 +2,35 @@ GEM
2 2 remote: http://rubygems.org/
3 3 specs:
4 4 SystemTimer (1.2.3)
5   - actionmailer (3.2.6)
6   - actionpack (= 3.2.6)
  5 + actionmailer (3.2.8)
  6 + actionpack (= 3.2.8)
7 7 mail (~> 2.4.4)
8 8 actionmailer_inline_css (1.3.1)
9 9 actionmailer (>= 3.0.0)
10 10 nokogiri (>= 1.4.4)
11 11 premailer (>= 1.7.1)
12   - actionpack (3.2.6)
13   - activemodel (= 3.2.6)
14   - activesupport (= 3.2.6)
  12 + actionpack (3.2.8)
  13 + activemodel (= 3.2.8)
  14 + activesupport (= 3.2.8)
15 15 builder (~> 3.0.0)
16 16 erubis (~> 2.7.0)
17   - journey (~> 1.0.1)
  17 + journey (~> 1.0.4)
18 18 rack (~> 1.4.0)
19 19 rack-cache (~> 1.2)
20 20 rack-test (~> 0.6.1)
21 21 sprockets (~> 2.1.3)
22   - activemodel (3.2.6)
23   - activesupport (= 3.2.6)
  22 + activemodel (3.2.8)
  23 + activesupport (= 3.2.8)
24 24 builder (~> 3.0.0)
25   - activerecord (3.2.6)
26   - activemodel (= 3.2.6)
27   - activesupport (= 3.2.6)
  25 + activerecord (3.2.8)
  26 + activemodel (= 3.2.8)
  27 + activesupport (= 3.2.8)
28 28 arel (~> 3.0.2)
29 29 tzinfo (~> 0.3.29)
30   - activeresource (3.2.6)
31   - activemodel (= 3.2.6)
32   - activesupport (= 3.2.6)
33   - activesupport (3.2.6)
  30 + activeresource (3.2.8)
  31 + activemodel (= 3.2.8)
  32 + activesupport (= 3.2.8)
  33 + activesupport (3.2.8)
34 34 i18n (~> 0.6)
35 35 multi_json (~> 1.0)
36 36 addressable (2.3.2)
... ... @@ -39,7 +39,13 @@ GEM
39 39 bson (1.6.2)
40 40 bson_ext (1.6.2)
41 41 bson (~> 1.6.2)
42   - builder (3.0.0)
  42 + builder (3.0.3)
  43 + capistrano (2.13.3)
  44 + highline
  45 + net-scp (>= 1.0.0)
  46 + net-sftp (>= 2.0.0)
  47 + net-ssh (>= 2.0.14)
  48 + net-ssh-gateway (>= 1.1.0)
43 49 capybara (1.1.2)
44 50 mime-types (>= 1.16)
45 51 nokogiri (>= 1.3.3)
... ... @@ -86,18 +92,19 @@ GEM
86 92 libxml-ruby (~> 2.0)
87 93 has_scope (0.5.1)
88 94 hashie (1.2.0)
  95 + highline (1.6.13)
89 96 hike (1.2.1)
90 97 hoptoad_notifier (2.4.11)
91 98 activesupport
92 99 builder
93 100 htmlentities (4.3.1)
94 101 httpauth (0.1)
95   - i18n (0.6.0)
  102 + i18n (0.6.1)
96 103 inherited_resources (1.3.1)
97 104 has_scope (~> 0.5.0)
98 105 responders (~> 0.6)
99 106 journey (1.0.4)
100   - json (1.7.4)
  107 + json (1.7.5)
101 108 jwt (0.1.5)
102 109 multi_json (>= 1.0)
103 110 kaminari (0.13.0)
... ... @@ -134,6 +141,13 @@ GEM
134 141 railties (>= 3.0.0)
135 142 multi_json (1.3.6)
136 143 multipart-post (1.1.5)
  144 + net-scp (1.0.4)
  145 + net-ssh (>= 1.99.1)
  146 + net-sftp (2.0.5)
  147 + net-ssh (>= 2.0.9)
  148 + net-ssh (2.5.2)
  149 + net-ssh-gateway (1.1.0)
  150 + net-ssh (>= 1.99.1)
137 151 nokogiri (1.5.5)
138 152 oa-core (0.3.2)
139 153 oauth2 (0.8.0)
... ... @@ -181,19 +195,19 @@ GEM
181 195 rack-ssl-enforcer (0.2.4)
182 196 rack-test (0.6.1)
183 197 rack (>= 1.0)
184   - rails (3.2.6)
185   - actionmailer (= 3.2.6)
186   - actionpack (= 3.2.6)
187   - activerecord (= 3.2.6)
188   - activeresource (= 3.2.6)
189   - activesupport (= 3.2.6)
  198 + rails (3.2.8)
  199 + actionmailer (= 3.2.8)
  200 + actionpack (= 3.2.8)
  201 + activerecord (= 3.2.8)
  202 + activeresource (= 3.2.8)
  203 + activesupport (= 3.2.8)
190 204 bundler (~> 1.0)
191   - railties (= 3.2.6)
  205 + railties (= 3.2.8)
192 206 rails_autolink (1.0.9)
193 207 rails (~> 3.1)
194   - railties (3.2.6)
195   - actionpack (= 3.2.6)
196   - activesupport (= 3.2.6)
  208 + railties (3.2.8)
  209 + actionpack (= 3.2.8)
  210 + activesupport (= 3.2.8)
197 211 rack-ssl (~> 1.3.2)
198 212 rake (>= 0.8.7)
199 213 rdoc (~> 3.4)
... ... @@ -244,7 +258,7 @@ GEM
244 258 daemons (>= 1.0.9)
245 259 eventmachine (>= 0.12.6)
246 260 rack (>= 1.0.0)
247   - thor (0.15.4)
  261 + thor (0.16.0)
248 262 tilt (1.3.3)
249 263 treetop (1.4.10)
250 264 polyglot
... ... @@ -275,6 +289,7 @@ DEPENDENCIES
275 289 actionmailer_inline_css (~> 1.3.0)
276 290 bson (= 1.6.2)
277 291 bson_ext (= 1.6.2)
  292 + capistrano
278 293 capybara
279 294 database_cleaner (~> 0.6.0)
280 295 debugger
... ... @@ -299,7 +314,7 @@ DEPENDENCIES
299 314 oruen_redmine_client
300 315 pivotal-tracker
301 316 rack-ssl-enforcer
302   - rails (= 3.2.6)
  317 + rails (= 3.2.8)
303 318 rails_autolink (~> 1.0.9)
304 319 ri_cal
305 320 rspec (~> 2.6)
... ...
app/assets/stylesheets/errbit.css
... ... @@ -841,15 +841,30 @@ table.comment tbody th {
841 841 height: 20px;
842 842 line-height: 0.5em;
843 843 }
  844 +table.comment th span, table.comment th img {
  845 + vertical-align: middle;
  846 +}
  847 +table.comment th span.comment-info {
  848 + line-height: 21px;
  849 +}
  850 +table.comment img.gravatar {
  851 + margin-right: 7px;
  852 +}
  853 +
844 854 table.comment tbody td {
845 855 background-color: #F9F9F9;
846 856 }
847 857 #content-comments a.destroy-comment {
848 858 color: #EE0000;
849 859 margin-right: 5px;
  860 + margin-top: 2px;
  861 + font-size: 21px;
  862 + line-height: 1;
  863 + float: right;
850 864 }
851 865 #content-comments a.destroy-comment:hover {
852 866 text-decoration: none;
  867 + color: #AA0000;
853 868 }
854 869 #content-comments #comment_submit {
855 870 margin-top: 15px;
... ... @@ -878,3 +893,12 @@ table.errs tr td.message .inline_comment em.commenter {
878 893  
879 894 .current.asc:after { content: ' ↑'; }
880 895 .current.desc:after { content: ' ↓'; }
  896 +
  897 +
  898 +table.users td {
  899 + vertical-align: middle;
  900 +}
  901 +table.users td img.gravatar {
  902 + vertical-align: middle;
  903 + margin-left: 3px;
  904 +}
... ...
app/helpers/errs_helper.rb
... ... @@ -13,5 +13,19 @@ module ErrsHelper
13 13 truncate(msg, :length => 300).scan(/.{1,5}/).map { |s| h(s) }.join("​").html_safe
14 14 end
15 15 end
  16 +
  17 + def gravatar_tag(email, options = {})
  18 + image_tag gravatar_url(email, options), :alt => email, :class => 'gravatar'
  19 + end
  20 +
  21 + def gravatar_url(email, options = {})
  22 + default_options = {
  23 + :d => Errbit::Config.gravatar_default,
  24 + }
  25 + options.reverse_merge! default_options
  26 + params = options.extract!(:s, :d).delete_if { |k, v| v.blank? }
  27 + email_hash = Digest::MD5.hexdigest(email)
  28 + "http://www.gravatar.com/avatar/#{email_hash}?#{params.to_query}"
  29 + end
16 30 end
17 31  
... ...
app/views/errs/show.html.haml
... ... @@ -28,9 +28,12 @@
28 28 %table.comment
29 29 %tr
30 30 %th
31   - %span= link_to '✘'.html_safe, app_err_comment_path(@app, @problem, comment), :method => :delete, :data => { :confirm => "Are sure you don't need this comment?" }, :class => "destroy-comment"
32   - = time_ago_in_words(comment.created_at, true) << " ago by "
33   - = link_to comment.user.email, user_path(comment.user)
  31 + - if Errbit::Config.use_gravatar
  32 + = gravatar_tag comment.user.email, :s => 24
  33 + %span.comment-info
  34 + = time_ago_in_words(comment.created_at, true) << " ago by "
  35 + = link_to comment.user.email, user_path(comment.user)
  36 + %span.delete= link_to '&#10008;'.html_safe, app_err_comment_path(@app, @problem, comment), :method => :delete, :data => { :confirm => "Are sure you don't need this comment?" }, :class => "destroy-comment"
34 37 %tr
35 38 %td= comment.body.gsub("\n", "<br>").html_safe
36 39 - if Errbit::Config.allow_comments_with_issue_tracker || !@app.issue_tracker_configured?
... ...
app/views/layouts/application.html.haml
... ... @@ -18,7 +18,7 @@
18 18 = render 'shared/navigation' if current_user
19 19 = render 'shared/session'
20 20 #content-wrapper
21   - #content-title{ :class => (yield :title_css_class).to_s }
  21 + #content-title{ :class => (yield :title_css_class).to_s, :style => (yield :title_style) }
22 22 %h1= yield :title
23 23 %span.meta= yield :meta
24 24 - if (action_bar = yield(:action_bar)).present?
... ... @@ -33,3 +33,4 @@
33 33 #footer= "Powered by #{link_to 'Errbit', 'http://github.com/errbit/errbit', :target => '_blank'}: the open source error catcher.".html_safe
34 34 = yield :scripts
35 35  
  36 += yield :before_title
36 37 \ No newline at end of file
... ...
app/views/users/index.html.haml
... ... @@ -2,9 +2,11 @@
2 2 - content_for :action_bar do
3 3 %span= link_to('Add a New User', new_user_path, :class => 'add')
4 4  
5   -%table
  5 +%table.users
6 6 %thead
7 7 %tr
  8 + - if Errbit::Config.use_gravatar
  9 + %th
8 10 %th Name
9 11 - if Errbit::Config.user_has_username
10 12 %th Username
... ... @@ -13,6 +15,8 @@
13 15 %tbody
14 16 - @users.each do |user|
15 17 %tr
  18 + - if Errbit::Config.use_gravatar
  19 + %td= gravatar_tag user.email, :s => 24
16 20 %td.nowrap= link_to user.name, user_path(user)
17 21 - if Errbit::Config.user_has_username
18 22 %td= user.username
... ...
app/views/users/show.html.haml
1 1 - content_for :title, @user.name
  2 +- if Errbit::Config.use_gravatar
  3 + - content_for :title_style do
  4 + background: url('#{gravatar_url @user.email, :s => 86}') no-repeat;
  5 + padding-left: 106px;
  6 +
2 7 - content_for :action_bar do
3 8 = render 'shared/link_github_account', :user => @user
4 9 %span= link_to('Add a New User', new_user_path, :class => 'add')
5 10 = link_to 'edit', edit_user_path(@user), :class => 'button'
6 11 = link_to 'destroy', user_path(@user), :method => :delete, :data => { :confirm => 'Seriously?' }, :class => 'button'
7 12  
8   -
9 13 %table.single_user
10 14 %tr
11 15 %th Email
... ...
config/config.example.yml
... ... @@ -39,6 +39,11 @@ user_has_username: false
39 39 # but you want to leave a short comment.
40 40 allow_comments_with_issue_tracker: true
41 41  
  42 +# Enable Gravatar.
  43 +use_gravatar: true
  44 +# Default Gravatar image, can be: mm, identicon, monsterid, wavatar, retro.
  45 +gravatar_default: identicon
  46 +
42 47 # Setup your deploy options for capistrano.
43 48 deployment:
44 49 hosts:
... ...
config/initializers/_load_config.rb
... ... @@ -13,6 +13,10 @@ unless defined?(Errbit::Config)
13 13 Errbit::Config.confirm_resolve_err = ENV['ERRBIT_CONFIRM_RESOLVE_ERR']
14 14 Errbit::Config.user_has_username = ENV['ERRBIT_USER_HAS_USERNAME']
15 15 Errbit::Config.allow_comments_with_issue_tracker = ENV['ERRBIT_ALLOW_COMMENTS_WITH_ISSUE_TRACKER']
  16 + Errbit::Config.enforce_ssl = ENV['ERRBIT_ENFORCE_SSL']
  17 +
  18 + Errbit::Config.use_gravatar = ENV['ERRBIT_USE_GRAVATAR']
  19 + Errbit::Config.gravatar_default = ENV['ERRBIT_GRAVATAR_DEFAULT']
16 20  
17 21 Errbit::Config.github_authentication = ENV['GITHUB_AUTHENTICATION']
18 22 Errbit::Config.github_client_id = ENV['GITHUB_CLIENT_ID']
... ...
config/initializers/omniauth.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +OmniAuth.config.logger = Rails.logger
... ...
db/migrate/20110422152027_move_notices_to_separate_collection.rb
... ... @@ -5,6 +5,10 @@ class MoveNoticesToSeparateCollection &lt; Mongoid::Migration
5 5 errs = mongo_db.collection("errs").find({ }, :fields => ["notices"])
6 6 errs.each do |err|
7 7 next unless err['notices']
  8 +
  9 + # This Err was created after the Problem->Err->Notice redesign
  10 + next if err['app_id'].nil? or err['problem_id']
  11 +
8 12 e = Err.find(err['_id'])
9 13 # disable email notifications
10 14 old_notify = e.app.notify_on_errs?
... ...
db/migrate/20120530005915_rename_klass_to_error_class.rb
1 1 class RenameKlassToErrorClass < Mongoid::Migration
2 2 def self.up
3 3 [Problem, Err, Notice].each do |model|
4   - model.collection.update({}, {'$rename' => {'klass' => 'error_class'}}, multi: true, safe: true)
  4 + model.collection.update({}, {'$rename' => {'klass' => 'error_class'}}, :multi => true, :safe => true)
5 5 end
6 6 end
7 7  
8 8 def self.down
9 9 [Problem, Err, Notice].each do |model|
10   - model.collection.update({}, {'$rename' => {'error_class' => 'klass'}}, multi: true, safe: true)
  10 + model.collection.update({}, {'$rename' => {'error_class' => 'klass'}}, :multi => true, :safe => true)
11 11 end
12 12 end
13 13 end
... ...
db/migrate/20120603112130_change_github_url_to_github_repo.rb
1 1 class ChangeGithubUrlToGithubRepo < Mongoid::Migration
2 2 def self.up
3   - App.collection.update({}, {'$rename' => {'github_url' => 'github_repo'}}, multi: true, safe: true)
  3 + App.collection.update({}, {'$rename' => {'github_url' => 'github_repo'}}, :multi => true, :safe => true)
4 4 App.all.each do |app|
5 5 app.send :normalize_github_repo
6 6 app.save
... ... @@ -8,7 +8,7 @@ class ChangeGithubUrlToGithubRepo &lt; Mongoid::Migration
8 8 end
9 9  
10 10 def self.down
11   - App.collection.update({}, {'$rename' => {'github_repo' => 'github_url'}}, multi: true, safe: true)
  11 + App.collection.update({}, {'$rename' => {'github_repo' => 'github_url'}}, :multi => true, :safe => true)
12 12 App.all.each do |app|
13 13 unless app.github_repo.include?("github.com")
14 14 app.update_attribute :github_url, "https://github.com/" << app.github_url
... ...
spec/controllers/notices_controller_spec.rb
... ... @@ -13,7 +13,7 @@ describe NoticesController do
13 13 @notice = App.report_error!(@xml)
14 14 end
15 15  
16   - it "generates a notice from xml [POST]" do
  16 + it "generates a notice from raw xml [POST]" do
17 17 App.should_receive(:report_error!).with(@xml).and_return(@notice)
18 18 request.should_receive(:raw_post).and_return(@xml)
19 19 post :create, :format => :xml
... ... @@ -24,6 +24,16 @@ describe NoticesController do
24 24 response.body.should match(%r{<url[^>]*>(.+)#{locate_path(@notice.id)}</url>})
25 25 end
26 26  
  27 + it "generates a notice from xml in a data param [POST]" do
  28 + App.should_receive(:report_error!).with(@xml).and_return(@notice)
  29 + post :create, :data => @xml, :format => :xml
  30 + response.should be_success
  31 + # Same RegExp from Airbrake::Sender#send_to_airbrake (https://github.com/airbrake/airbrake/blob/master/lib/airbrake/sender.rb#L53)
  32 + # Inspired by https://github.com/airbrake/airbrake/blob/master/test/sender_test.rb
  33 + response.body.should match(%r{<id[^>]*>#{@notice.id}</id>})
  34 + response.body.should match(%r{<url[^>]*>(.+)#{locate_path(@notice.id)}</url>})
  35 + end
  36 +
27 37 it "generates a notice from xml [GET]" do
28 38 App.should_receive(:report_error!).with(@xml).and_return(@notice)
29 39 get :create, :data => @xml, :format => :xml
... ...
spec/helpers/errs_helper_spec.rb
... ... @@ -9,4 +9,27 @@ describe ErrsHelper do
9 9 truncated.should_not include('<', '>')
10 10 end
11 11 end
  12 +
  13 + describe "#gravatar_tag" do
  14 + let(:email) { "gravatar@example.com" }
  15 + let(:email_hash) { Digest::MD5.hexdigest email }
  16 + let(:base_url) { "http://www.gravatar.com/avatar/#{email_hash}" }
  17 +
  18 + context "default config" do
  19 + before do
  20 + Errbit::Config.stub(:use_gravatar).and_return(true)
  21 + Errbit::Config.stub(:gravatar_default).and_return('identicon')
  22 + end
  23 +
  24 + it "should render image_tag with correct alt and src" do
  25 + expected = "<img alt=\"#{email}\" class=\"gravatar\" src=\"#{base_url}?d=identicon&amp;s=48\" />"
  26 + helper.gravatar_tag(email, :s => 48).should eq(expected)
  27 + end
  28 +
  29 + it "should override :d" do
  30 + expected = "<img alt=\"#{email}\" class=\"gravatar\" src=\"#{base_url}?d=retro&amp;s=48\" />"
  31 + helper.gravatar_tag(email, :d => 'retro', :s => 48).should eq(expected)
  32 + end
  33 + end
  34 + end
12 35 end
... ...
spec/views/errs/show.html.haml_spec.rb
... ... @@ -90,6 +90,7 @@ describe &quot;errs/show.html.haml&quot; do
90 90 describe "content_for :comments with comments disabled for configured issue tracker" do
91 91 before do
92 92 Errbit::Config.stub(:allow_comments_with_issue_tracker).and_return(false)
  93 + Errbit::Config.stub(:use_gravatar).and_return(true)
93 94 end
94 95  
95 96 it 'should display comments and new comment form when no issue tracker' do
... ... @@ -99,6 +100,7 @@ describe &quot;errs/show.html.haml&quot; do
99 100 render
100 101  
101 102 view.content_for(:comments).should include('Test comment')
  103 + view.content_for(:comments).should have_selector('img[src^="http://www.gravatar.com/avatar"]')
102 104 view.content_for(:comments).should include('Add a comment')
103 105 end
104 106  
... ... @@ -117,6 +119,7 @@ describe &quot;errs/show.html.haml&quot; do
117 119 render
118 120  
119 121 view.content_for(:comments).should include('Test comment')
  122 + view.content_for(:comments).should have_selector('img[src^="http://www.gravatar.com/avatar"]')
120 123 view.content_for(:comments).should_not include('Add a comment')
121 124 end
122 125 end
... ...
spec/views/users/show.html.haml_spec.rb
... ... @@ -2,7 +2,7 @@ require &#39;spec_helper&#39;
2 2  
3 3 describe 'users/show.html.haml' do
4 4 let(:user) do
5   - stub_model(User, :created_at => Time.now)
  5 + stub_model(User, :created_at => Time.now, :email => "test@example.com")
6 6 end
7 7  
8 8 before do
... ...