Commit a3fb360ceee40b08d9bd3e753bbe605de1bc411b

Authored by Pavel Forkert
2 parents 60425256 0029a957
Exists in master and in 1 other branch production

Merge branch 'master' of github.com:fxposter/errbit

@@ -100,58 +100,58 @@ for you. Checkout [Hoptoad](http://hoptoadapp.com) from the guys over at @@ -100,58 +100,58 @@ for you. Checkout [Hoptoad](http://hoptoadapp.com) from the guys over at
100 100
101 **Configuring LDAP authentication:** 101 **Configuring LDAP authentication:**
102 102
103 - 1. Add the following line to Errbit's Gemfile: 103 + 1. In `config/config.yml`, set `user_has_username` to `true`
  104 + 2. Follow the instructions at https://github.com/cschiewek/devise_ldap_authenticatable
  105 + to set up the devise_ldap_authenticatable gem.
104 106
105 - gem "devise_ldap_authenticatable", :git => "git://github.com/cschiewek/devise_ldap_authenticatable.git" 107 + 3. If you are authenticating by `username`, you will need to set the user's email
  108 + after authentication. You can do this by adding the following lines to `app/models/user.rb`:
106 109
107 - 2. Install new dependencies  
108 -  
109 - bundle install  
110 -  
111 - 3. Run the rails generator for `devise_ldap_authenticatable`  
112 -  
113 - rails generate devise_ldap_authenticatable:install --advanced  
114 -  
115 - 4. Configure your LDAP settings in `config/initializers/devise.rb`.  
116 -  
117 - 5. If you want to authenticate via `username`, then add the following lines to `app/models/user.rb`:  
118 -  
119 - field :username  
120 - before_save :set_ldap_email  
121 - def set_ldap_email  
122 - self.email = Devise::LdapAdapter.get_ldap_param(self.username, "mail")  
123 - end  
124 -  
125 -To learn more, please follow the instructions at https://github.com/cschiewek/devise_ldap_authenticatable 110 + before_save :set_ldap_email
  111 + def set_ldap_email
  112 + self.email = Devise::LdapAdapter.get_ldap_param(self.username, "mail")
  113 + end
126 114
127 115
128 Upgrading 116 Upgrading
129 --------- 117 ---------
130 -*Note*: If upgrading from a version of Errbit that used Notices embedded in Errs please run: 118 +*Note*: When upgrading Errbit, please run:
131 119
132 1. git pull origin master ( assuming origin is the github.com/jdpace/errbit repo ) 120 1. git pull origin master ( assuming origin is the github.com/jdpace/errbit repo )
133 2. rake db:migrate 121 2. rake db:migrate
134 122
135 -Lighthouseapp integration 123 +If we change the way that data is stored, this will run any migrations to bring your database up to date.
  124 +
  125 +
  126 +Lighthouseapp Integration
136 ------------------------- 127 -------------------------
137 128
138 * Account is the name of your subdomain, i.e. **litcafe** for project at http://litcafe.lighthouseapp.com/projects/73466-face/overview 129 * Account is the name of your subdomain, i.e. **litcafe** for project at http://litcafe.lighthouseapp.com/projects/73466-face/overview
139 * Errbit uses token-based authentication. Get your API Token or visit [http://help.lighthouseapp.com/kb/api/how-do-i-get-an-api-token](http://help.lighthouseapp.com/kb/api/how-do-i-get-an-api-token) to learn how to get it. 130 * Errbit uses token-based authentication. Get your API Token or visit [http://help.lighthouseapp.com/kb/api/how-do-i-get-an-api-token](http://help.lighthouseapp.com/kb/api/how-do-i-get-an-api-token) to learn how to get it.
140 * Project id is number identifier of your project, i.e. **73466** for project at http://litcafe.lighthouseapp.com/projects/73466-face/overview 131 * Project id is number identifier of your project, i.e. **73466** for project at http://litcafe.lighthouseapp.com/projects/73466-face/overview
141 132
142 -Redmine integration 133 +Redmine Integration
143 ------------------------- 134 -------------------------
144 135
145 * Account is the host of your redmine installation, i.e. **http://redmine.org** 136 * Account is the host of your redmine installation, i.e. **http://redmine.org**
146 * Errbit uses token-based authentication. Get your API Key or visit [http://www.redmine.org/projects/redmine/wiki/Rest_api#Authentication](http://www.redmine.org/projects/redmine/wiki/Rest_api#Authentication) to learn how to get it. 137 * Errbit uses token-based authentication. Get your API Key or visit [http://www.redmine.org/projects/redmine/wiki/Rest_api#Authentication](http://www.redmine.org/projects/redmine/wiki/Rest_api#Authentication) to learn how to get it.
147 * Project id is an identifier of your project, i.e. **chilliproject** for project at http://www.redmine.org/projects/chilliproject 138 * Project id is an identifier of your project, i.e. **chilliproject** for project at http://www.redmine.org/projects/chilliproject
148 139
149 -Pivotal Tracker integration 140 +Pivotal Tracker Integration
150 ------------------------- 141 -------------------------
151 142
152 * Errbit uses token-based authentication. Get your API Key or visit [http://www.pivotaltracker.com/help/api](http://www.pivotaltracker.com/help/api) to learn how to get it. 143 * Errbit uses token-based authentication. Get your API Key or visit [http://www.pivotaltracker.com/help/api](http://www.pivotaltracker.com/help/api) to learn how to get it.
153 * Project id is an identifier of your project, i.e. **24324** for project at http://www.pivotaltracker.com/projects/24324 144 * Project id is an identifier of your project, i.e. **24324** for project at http://www.pivotaltracker.com/projects/24324
154 145
  146 +Thoughtworks Mingle Integration
  147 +-------------------------------
  148 +
  149 +* Account is the host of your mingle installation. i.e. **https://mingle.example.com** *note*: You should use SSL if possible.
  150 +* Errbit uses 'sign-in name' & password authentication. You may want to set up an **errbit** user with limited rights.
  151 +* Project id is the identifier of your project, i.e. **awesomeapp** for project at https://mingle.example.com/projects/awesomeapp
  152 +* Card properties are comma separated key value pairs. You must specify a 'card_type', but anything else is optional. i.e. card_type = Defect, status = Open, priority = Essential
  153 +
  154 +
155 TODO 155 TODO
156 ---- 156 ----
157 157
app/models/user.rb
@@ -7,6 +7,7 @@ class User @@ -7,6 +7,7 @@ class User
7 :recoverable, :rememberable, :trackable, 7 :recoverable, :rememberable, :trackable,
8 :validatable, :token_authenticatable 8 :validatable, :token_authenticatable
9 9
  10 + field :email
10 field :name 11 field :name
11 field :admin, :type => Boolean, :default => false 12 field :admin, :type => Boolean, :default => false
12 field :per_page, :type => Fixnum, :default => PER_PAGE 13 field :per_page, :type => Fixnum, :default => PER_PAGE
@@ -18,6 +19,11 @@ class User @@ -18,6 +19,11 @@ class User
18 19
19 attr_protected :admin 20 attr_protected :admin
20 21
  22 + if Errbit::Config.user_has_username
  23 + field :username
  24 + validates_presence_of :username
  25 + end
  26 +
21 # Mongoid doesn't seem to currently support 27 # Mongoid doesn't seem to currently support
22 # referencing embedded documents 28 # referencing embedded documents
23 def watchers 29 def watchers
@@ -45,3 +51,4 @@ class User @@ -45,3 +51,4 @@ class User
45 watchers.each(&:destroy) 51 watchers.each(&:destroy)
46 end 52 end
47 end 53 end
  54 +
app/views/errs/_table.html.haml
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 - if current_page?(:controller => 'errs') 15 - if current_page?(:controller => 'errs')
16 %span.environment= link_to err.environment, errs_path(environment: err.environment) 16 %span.environment= link_to err.environment, errs_path(environment: err.environment)
17 - else 17 - else
18 - %span.environment= link_to err.environment, app_path(environment: err.environment) 18 + %span.environment= link_to err.environment, app_path(err.app, environment: err.environment)
19 %td.message 19 %td.message
20 = link_to err.message, app_err_path(err.app, err) 20 = link_to err.message, app_err_path(err.app, err)
21 %em= err.where 21 %em= err.where
app/views/users/_fields.html.haml
@@ -3,7 +3,12 @@ @@ -3,7 +3,12 @@
3 .required 3 .required
4 = f.label :name 4 = f.label :name
5 = f.text_field :name 5 = f.text_field :name
6 - 6 +
  7 +- if Errbit::Config.user_has_username
  8 + .required
  9 + = f.label :username
  10 + = f.text_field :username
  11 +
7 .required 12 .required
8 = f.label :email 13 = f.label :email
9 = f.text_field :email 14 = f.text_field :email
@@ -11,11 +16,11 @@ @@ -11,11 +16,11 @@
11 .required 16 .required
12 = f.label 'Entries per page' 17 = f.label 'Entries per page'
13 = f.select :per_page, [10, 20, 30, 50, 75, 100] 18 = f.select :per_page, [10, 20, 30, 50, 75, 100]
14 - 19 +
15 .required 20 .required
16 = f.label :password 21 = f.label :password
17 = f.password_field :password 22 = f.password_field :password
18 - 23 +
19 .required 24 .required
20 = f.label :password_confirmation 25 = f.label :password_confirmation
21 = f.password_field :password_confirmation 26 = f.password_field :password_confirmation
@@ -23,4 +28,5 @@ @@ -23,4 +28,5 @@
23 - if current_user.admin? 28 - if current_user.admin?
24 .checkbox 29 .checkbox
25 = f.check_box :admin 30 = f.check_box :admin
26 - = f.label :admin, 'Admin?'  
27 \ No newline at end of file 31 \ No newline at end of file
  32 + = f.label :admin, 'Admin?'
  33 +
app/views/users/index.html.haml
@@ -6,13 +6,17 @@ @@ -6,13 +6,17 @@
6 %thead 6 %thead
7 %tr 7 %tr
8 %th Name 8 %th Name
  9 + - if Errbit::Config.user_has_username
  10 + %th Username
9 %th.main Email 11 %th.main Email
10 %th Admin? 12 %th Admin?
11 %tbody 13 %tbody
12 - @users.each do |user| 14 - @users.each do |user|
13 %tr 15 %tr
14 %td.nowrap= link_to user.name, user_path(user) 16 %td.nowrap= link_to user.name, user_path(user)
  17 + - if Errbit::Config.user_has_username
  18 + %td= user.username
15 %td= user.email 19 %td= user.email
16 %td= user.admin? ? 'Y' : 'N' 20 %td= user.admin? ? 'Y' : 'N'
17 = will_paginate @users, :previous_label => '« Previous', :next_label => 'Next »' 21 = will_paginate @users, :previous_label => '« Previous', :next_label => 'Next »'
18 -  
19 \ No newline at end of file 22 \ No newline at end of file
  23 +
app/views/users/show.html.haml
1 - content_for :title, @user.name 1 - content_for :title, @user.name
2 - content_for :action_bar do 2 - content_for :action_bar do
  3 + %span= link_to('Add a New User', new_user_path, :class => 'add')
3 = link_to 'edit', edit_user_path(@user), :class => 'button' 4 = link_to 'edit', edit_user_path(@user), :class => 'button'
4 = link_to 'destroy', user_path(@user), :method => :delete, :confirm => 'Seriously?', :class => 'button' 5 = link_to 'destroy', user_path(@user), :method => :delete, :confirm => 'Seriously?', :class => 'button'
5 6
@@ -7,9 +8,14 @@ @@ -7,9 +8,14 @@
7 %tr 8 %tr
8 %th Email 9 %th Email
9 %td.main= @user.email 10 %td.main= @user.email
  11 + - if Errbit::Config.user_has_username
  12 + %tr
  13 + %th Username
  14 + %td.main= @user.username
10 %tr 15 %tr
11 %th Admin? 16 %th Admin?
12 %td= @user.admin? ? 'Y' : 'N' 17 %td= @user.admin? ? 'Y' : 'N'
13 %tr 18 %tr
14 %th Created 19 %th Created
15 - %td= @user.created_at.to_s(:micro)  
16 \ No newline at end of file 20 \ No newline at end of file
  21 + %td= @user.created_at.to_s(:micro)
  22 +
config/config.example.yml
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 # be copied to shared/config on the server when 6 # be copied to shared/config on the server when
7 # `cap deploy:setup` is ran the first time. Be sure 7 # `cap deploy:setup` is ran the first time. Be sure
8 # to place production specific settings there 8 # to place production specific settings there
  9 +# You will need to restart the server after changing any settings.
9 10
10 # The host of your errbit server 11 # The host of your errbit server
11 host: errbit.example.com 12 host: errbit.example.com
@@ -14,8 +15,8 @@ host: errbit.example.com @@ -14,8 +15,8 @@ host: errbit.example.com
14 # will be sent from. 15 # will be sent from.
15 email_from: errbit@example.com 16 email_from: errbit@example.com
16 17
17 -# if you turn on this option, email_at_notices will be configured on per app basis  
18 -# at App edit page 18 +# If you turn on this option, email_at_notices can be
  19 +# configured on a per app basis, at the App edit page
19 per_app_email_at_notices: false 20 per_app_email_at_notices: false
20 21
21 # Configure when emails are sent for an error. 22 # Configure when emails are sent for an error.
@@ -23,4 +24,10 @@ per_app_email_at_notices: false @@ -23,4 +24,10 @@ per_app_email_at_notices: false
23 # an email notification. 24 # an email notification.
24 email_at_notices: [1, 10, 100] 25 email_at_notices: [1, 10, 100]
25 26
  27 +# Configure whether or not the user should be prompted before resolving an error.
26 confirm_resolve_err: true 28 confirm_resolve_err: true
  29 +
  30 +# Add an optional 'username' field to Users.
  31 +# Helpful if you want to plug in your own authentication strategy.
  32 +user_has_username: false
  33 +
config/initializers/_load_config.rb
@@ -14,7 +14,8 @@ if ENV['HEROKU'] @@ -14,7 +14,8 @@ if ENV['HEROKU']
14 :domain => ENV['SENDGRID_DOMAIN'] 14 :domain => ENV['SENDGRID_DOMAIN']
15 } 15 }
16 else 16 else
17 - yaml = File.read(Rails.root.join('config','config.yml')) 17 + config_file = Rails.env == "test" ? "config.example.yml" : "config.yml"
  18 + yaml = File.read(Rails.root.join('config', config_file))
18 config = YAML.load(yaml) 19 config = YAML.load(yaml)
19 20
20 config.merge!(config.delete(Rails.env)) if config.has_key?(Rails.env) 21 config.merge!(config.delete(Rails.env)) if config.has_key?(Rails.env)
config/initializers/devise.rb
@@ -20,7 +20,7 @@ Devise.setup do |config| @@ -20,7 +20,7 @@ Devise.setup do |config|
20 # authenticating an user, both parameters are required. Remember that those 20 # authenticating an user, both parameters are required. Remember that those
21 # parameters are used only when authenticating and not when retrieving from 21 # parameters are used only when authenticating and not when retrieving from
22 # session. If you need permissions, you should implement that in a before filter. 22 # session. If you need permissions, you should implement that in a before filter.
23 - # config.authentication_keys = [ :email ] 23 + config.authentication_keys = [ Errbit::Config.user_has_username ? :username : :email ]
24 24
25 # Tell if authentication through request.params is enabled. True by default. 25 # Tell if authentication through request.params is enabled. True by default.
26 # config.params_authenticatable = true 26 # config.params_authenticatable = true
@@ -140,3 +140,4 @@ Devise.setup do |config| @@ -140,3 +140,4 @@ Devise.setup do |config|
140 # manager.default_strategies(:scope => :user).unshift :twitter_oauth 140 # manager.default_strategies(:scope => :user).unshift :twitter_oauth
141 # end 141 # end
142 end 142 end
  143 +
config/initializers/overrides.rb
1 require Rails.root.join('lib/overrides/mongoid/relations/builder.rb') 1 require Rails.root.join('lib/overrides/mongoid/relations/builder.rb')
  2 +require Rails.root.join('lib/overrides/devise/failure_app.rb')
  3 +
config/initializers/secret_token.rb
@@ -4,4 +4,5 @@ @@ -4,4 +4,5 @@
4 # If you change this key, all old signed cookies will become invalid! 4 # If you change this key, all old signed cookies will become invalid!
5 # Make sure the secret is at least 30 characters and all random, 5 # Make sure the secret is at least 30 characters and all random,
6 # no regular words or you'll be exposed to dictionary attacks. 6 # no regular words or you'll be exposed to dictionary attacks.
7 -Errbit::Application.config.secret_token = '41f6b3871b375769786c379a3e542d67a7a234926f926778ed634f40a9480ba6d7b0768993e9852aafcaa73d6b8ddd2ed3b46208b92305e8c21936574f74a9a4' 7 +Errbit::Application.config.secret_token = '6b74778101638fa9c156b3928c9492fb2481ab842538bea838d21f9c9993f649f5806449584266d413d0b2f1104162b3066a86512ed71ededd627cd41f939614'
  8 +
config/locales/devise.en.yml
@@ -10,7 +10,10 @@ en: @@ -10,7 +10,10 @@ en:
10 unauthenticated: 'You need to sign in before continuing.' 10 unauthenticated: 'You need to sign in before continuing.'
11 unconfirmed: 'You have to confirm your account before continuing.' 11 unconfirmed: 'You have to confirm your account before continuing.'
12 locked: 'Your account is locked.' 12 locked: 'Your account is locked.'
13 - invalid: 'Invalid email or password.' 13 + invalid: 'Invalid login details.'
  14 + user:
  15 + email_invalid: 'Invalid email or password.'
  16 + username_invalid: 'Invalid username or password.'
14 invalid_token: 'Invalid authentication token.' 17 invalid_token: 'Invalid authentication token.'
15 timeout: 'Your session expired, please sign in again to continue.' 18 timeout: 'Your session expired, please sign in again to continue.'
16 inactive: 'Your account was not activated yet.' 19 inactive: 'Your account was not activated yet.'
@@ -37,3 +40,4 @@ en: @@ -37,3 +40,4 @@ en:
37 subject: 'Reset password instructions' 40 subject: 'Reset password instructions'
38 unlock_instructions: 41 unlock_instructions:
39 subject: 'Unlock Instructions' 42 subject: 'Unlock Instructions'
  43 +
@@ -2,10 +2,12 @@ puts "Seeding database" @@ -2,10 +2,12 @@ puts "Seeding database"
2 puts "-------------------------------" 2 puts "-------------------------------"
3 3
4 # Create an initial Admin User 4 # Create an initial Admin User
  5 +admin_username = "errbit"
5 admin_email = "errbit@#{Errbit::Config.host}" 6 admin_email = "errbit@#{Errbit::Config.host}"
6 admin_pass = 'password' 7 admin_pass = 'password'
7 8
8 puts "Creating an initial admin user:" 9 puts "Creating an initial admin user:"
  10 +puts "-- username: #{admin_username}" if Errbit::Config.user_has_username
9 puts "-- email: #{admin_email}" 11 puts "-- email: #{admin_email}"
10 puts "-- password: #{admin_pass}" 12 puts "-- password: #{admin_pass}"
11 puts "" 13 puts ""
@@ -16,6 +18,8 @@ user = User.where(:email => admin_email).first || User.new({ @@ -16,6 +18,8 @@ user = User.where(:email => admin_email).first || User.new({
16 :password => admin_pass, 18 :password => admin_pass,
17 :password_confirmation => admin_pass 19 :password_confirmation => admin_pass
18 }) 20 })
  21 +user.username = admin_username if Errbit::Config.user_has_username
19 22
20 user.admin = true 23 user.admin = true
21 user.save! 24 user.save!
  25 +
lib/overrides/devise/failure_app.rb 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +Devise::FailureApp.class_eval do
  2 + protected
  3 + # Handles both 'email_invalid' and 'username_invalid' messages.
  4 + def i18n_message(default = nil)
  5 + message = warden.message || warden_options[:message] || default || :unauthenticated
  6 +
  7 + if message.is_a?(Symbol)
  8 + I18n.t(:"#{scope}.#{Devise.authentication_keys.first}_#{message}", :resource_name => scope,
  9 + :scope => "devise.failure", :default => [message, message.to_s])
  10 + else
  11 + message.to_s
  12 + end
  13 + end
  14 +end
  15 +
public/javascripts/form.js
@@ -66,12 +66,16 @@ function removeNestedItem() { @@ -66,12 +66,16 @@ function removeNestedItem() {
66 66
67 67
68 function activateTypeSelector(field_class, section_class) { 68 function activateTypeSelector(field_class, section_class) {
69 - section_class = section_class || field_class+"_params"; // section_class can be deduced if not given 69 + var section_class = section_class || field_class+"_params"; // section_class can be deduced if not given
  70 + // disable all inactive tabs to avoid sending its values on server
  71 + $('div.'+field_class+' > div.'+section_class).not('.chosen').find('input')
  72 + .attr('disabled','disabled').val('');
  73 +
70 $('div.'+field_class+' input[name*='+field_class+'_type]').live('click', function(){ 74 $('div.'+field_class+' input[name*='+field_class+'_type]').live('click', function(){
71 var chosen = $(this).val(); 75 var chosen = $(this).val();
72 var wrapper = $(this).closest('.nested'); 76 var wrapper = $(this).closest('.nested');
73 - wrapper.find('div.chosen.'+section_class).removeClass('chosen');  
74 - wrapper.find('div.'+section_class+'.'+chosen).addClass('chosen'); 77 + wrapper.find('div.chosen.'+section_class).removeClass('chosen').find('input').attr('disabled','disabled');
  78 + wrapper.find('div.'+section_class+'.'+chosen).addClass('chosen').find('input').removeAttr('disabled');
75 }); 79 });
76 } 80 }
77 81
public/javascripts/notifier.js
@@ -6,7 +6,7 @@ var Errbit = { @@ -6,7 +6,7 @@ var Errbit = {
6 <notifier>\ 6 <notifier>\
7 <name>errbit_notifier_js</name>\ 7 <name>errbit_notifier_js</name>\
8 <version>2.0</version>\ 8 <version>2.0</version>\
9 - <url>http://NOTIFIER_HOST</url>\ 9 + <url>https://github.com/jdpace/errbit</url>\
10 </notifier>\ 10 </notifier>\
11 <error>\ 11 <error>\
12 <class>EXCEPTION_CLASS</class>\ 12 <class>EXCEPTION_CLASS</class>\
@@ -30,7 +30,7 @@ var Errbit = { @@ -30,7 +30,7 @@ var Errbit = {
30 notify: function(error) { 30 notify: function(error) {
31 var xml = escape(Errbit.generateXML(error)); 31 var xml = escape(Errbit.generateXML(error));
32 var host = Errbit.host || 'github.com/jdpace/errbit'; 32 var host = Errbit.host || 'github.com/jdpace/errbit';
33 - var url = '//' + host + '/notifier_api/v2/notices?data=' + xml; 33 + var url = '//' + host + '/notifier_api/v2/notices.xml?data=' + xml;
34 var request = document.createElement('iframe'); 34 var request = document.createElement('iframe');
35 35
36 request.style.width = '1px'; 36 request.style.width = '1px';
@@ -103,7 +103,6 @@ var Errbit = { @@ -103,7 +103,6 @@ var Errbit = {
103 } 103 }
104 104
105 xml = xml.replace('</request>', data + '</request>') 105 xml = xml.replace('</request>', data + '</request>')
106 - .replace('NOTIFIER_HOST', host)  
107 .replace('REQUEST_URL', url) 106 .replace('REQUEST_URL', url)
108 .replace('REQUEST_ACTION', action) 107 .replace('REQUEST_ACTION', action)
109 .replace('REQUEST_COMPONENT', component); 108 .replace('REQUEST_COMPONENT', component);