openstax_rescue_from 0.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 8c0c0a01fc9e68148d1e6edee85fe7676c0a4378
4
- data.tar.gz: 7d233b3e0bff69be9e33b708b48d8470941c5927
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OWZjZTY5NGM1OGJiYmY4MzliNTgzMWZiZWU1NjMyMDU2Mzg3Y2Q2NA==
5
+ data.tar.gz: !binary |-
6
+ ODQ4NjFmMTMxNzJmMjk3ZjJiMjFlOWUzYmQxOWZmMjkzMTQzNTg2ZQ==
5
7
  SHA512:
6
- metadata.gz: a51f638e3fd3d3defffd71833c798001b2486be1fd8f17090490357065eac39fc1f7542a1ad4100f1179c0e8cd95a14719232521eb7c5eae6950684047ac7c37
7
- data.tar.gz: 688fbe57b528e091c95b8efe66ab59f8a0ea1c12650c818f481b9d3fa387d12d3bc68d7181944d626b445808520bcbeaa3e5d581101cad387cec0e74c1d6ea56
8
+ metadata.gz: !binary |-
9
+ YTAzMWVjZGM0ODJlZGM1NjZkMmMyN2MwNzU1OGUzNTU0N2EyYzVkMWYxNWZm
10
+ MmMyZDFiYzYwNTI4OTU2OTFmZTQ3MmYyOGNiOWNiZjZhM2NiYjYwZWMzZWYx
11
+ MWVkMWU3YTg4NmQ3NjllNjYwMjlkZDdlZWU3Yzc3MTFlZmJlYmE=
12
+ data.tar.gz: !binary |-
13
+ ZDE1ODgyNGUwZDRlNTkyZDY5NWM1M2NhY2VlZjZiMDFmM2M1YTMwZDMxZmJl
14
+ ZGU0YTE1YzY2YjU4ZWU5YmYyMTQxYzY4M2I2YWNhZDZkNWZjN2M0MWM5MmIz
15
+ MTc5YjJjNmM4OWUzOGNiM2M5MmM1ZmVhOGNjNDk2ZTcwYTVkODU=
data/.gitignore CHANGED
@@ -6,8 +6,8 @@
6
6
  /doc/
7
7
  /pkg/
8
8
  /spec/reports/
9
- /tmp/
10
- log/*.log
9
+ tmp/
10
+ *.log
11
11
  .DS_Store
12
12
  *~
13
13
 
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ openstax-rescue-from
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3
data/.travis.yml CHANGED
@@ -1,10 +1,20 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.2.3
4
+ - "1.9.3"
5
+ - "2.2.3"
5
6
  cache: bundler
6
7
  bundler_args: --retry=6
7
- before_install: gem install bundler -v 1.10.6
8
- branches:
9
- only:
10
- - master
8
+ script:
9
+ - bundle exec rake
10
+ notifications:
11
+ email: false
12
+ addons:
13
+ postgresql: "9.3"
14
+ before_install:
15
+ - gem install bundler
16
+ before_script:
17
+ - export OXT_DB_USER=postgres
18
+ - export OXT_DB_PASS=
19
+ - export OXT_TEST_DB=travis_ci_test
20
+ - bundle exec rake db:create:all db:migrate
data/README.md CHANGED
@@ -1,15 +1,13 @@
1
1
  # RescueFrom
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/rescue_from`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ This is the gem that brings together disparate systems within OpenStax and abstracts consistent exception rescuing with html and json responses, and email notifying
6
4
 
7
5
  ## Installation
8
6
 
9
7
  Add this line to your application's Gemfile:
10
8
 
11
9
  ```ruby
12
- gem 'rescue_from'
10
+ gem 'rescue_from', '~> 1.0.0'
13
11
  ```
14
12
 
15
13
  And then execute:
@@ -22,20 +20,170 @@ Or install it yourself as:
22
20
 
23
21
  ## Usage
24
22
 
25
- TODO: Write usage instructions here
23
+ Run the install generator to get the config initializer
24
+
25
+ ```
26
+ $ rails g open_stax:rescue_from:install
27
+ ```
28
+
29
+ Declare that you want to use the openstax exception rescuer in your controller, preferably your `ApplicationController`
30
+
31
+ ```ruby
32
+ class ApplicationController < ActionController::Base
33
+
34
+ # ...
35
+
36
+ use_openstax_exception_rescue
37
+
38
+ # ...
39
+
40
+ # Override the rescued hook which is called when configuration.raise_exceptions is false
41
+ # (See 'Controller hook')
42
+ #
43
+ # def openstax_exception_rescued(exception_proxy)
44
+ # app_name = openstax_rescue_config.app_name
45
+ # # RescueFrom.configuration private method available to you
46
+ #
47
+ # respond_to do |f|
48
+ # f.xml { render text: "I respond strangely to the XML format!",
49
+ # status: exception_proxy.status }
50
+ # end
51
+ # end
52
+ end
53
+ ```
54
+
55
+ ## Configuration
56
+
57
+ This configuration, which is placed in `./config/initializers/rescue_from.rb` by the install generator, shows the defaults:
58
+
59
+ ```ruby
60
+ OpenStax::RescueFrom.configure do |config|
61
+ config.raise_exceptions = ![false, 'false'].include?(ENV['RAISE_EXCEPTIONS']) ||
62
+ Rails.application.config.consider_all_requests_local
63
+
64
+ config.app_name = ENV['APP_NAME']
65
+ config.app_env = ENV['APP_ENV']
66
+ config.contact_name = ENV['EXCEPTION_CONTACT_NAME']
67
+ # can be a name, or a web/email address. See 'View helper' below
68
+
69
+ config.notifier = ExceptionNotifier
70
+
71
+ config.html_error_template_path = 'errors/any'
72
+ config.html_error_template_layout_name = 'application'
73
+
74
+ config.email_prefix = "[#{app_name}] (#{app_env}) "
75
+ config.sender_address = ENV['EXCEPTION_SENDER']
76
+ config.exception_recipients = ENV['EXCEPTION_RECIPIENTS']
77
+ end
78
+ ```
79
+
80
+ ## Registering exceptions
81
+
82
+ In `./config/initializers/rescue_from.rb` it is recommended you register your exceptions
83
+
84
+ Note that any unregistered exceptions rescued during run-time will be registered with the default options. See below.
85
+
86
+ ```ruby
87
+ require 'openstax_rescue_from'
88
+
89
+ OpenStax::RescueFrom.configure do |c|
90
+ # c.app_name ...
91
+ end
92
+
93
+ # OpenStax::RescueFrom#register_exception default options:
94
+ #
95
+ # { notify: true,
96
+ # status: :internal_server_error,
97
+ # extras: ->(exception) { {} } }
98
+ #
99
+ # Any unregistered exceptions rescued during run-time
100
+ # will be registered during rescue with the options above
101
+
102
+ OpenStax::RescueFrom.register_exception('SecurityTransgression',
103
+ notify: false,
104
+ status: :forbidden)
105
+
106
+ OpenStax::RescueFrom.register_exception(ActiveRecord::NotFound,
107
+ notify: false,
108
+ status: :not_found)
109
+
110
+ OpenStax::RescueFrom.register_exception('OAuth2::Error',
111
+ extras: ->(exception) {
112
+ { headers: exception.response.headers,
113
+ status: exception.response.status,
114
+ body: exception.response.body }
115
+ })
116
+
117
+ OpenStax::RescueFrom.translate_status_codes({
118
+ forbidden: 'You are not allowed to access this.',
119
+ not_found: 'We couldn't find what you asked for.',
120
+ })
121
+ #
122
+ # Default:
123
+ # internal_server_error: "Sorry, #{OpenStax::RescueFrom.configuration.app_name} had some unexpected trouble with your request."
124
+ ```
125
+
126
+ ## Controller hook
127
+ ```ruby
128
+ #
129
+ # -- Mixed in Controller module instance method --
130
+ #
131
+ # -- this method is ONLY called when Exceptions are not raised --
132
+ #
133
+ # -- check your OpenStax::RescueFrom.configuration.raise_exceptions setting --
134
+ #
135
+
136
+ def openstax_exception_rescued(exception_proxy)
137
+ @message = exception_proxy.friendly_message
138
+ @status = exception_proxy.status
139
+ @error_id = exception_proxy.error_id
140
+
141
+ respond_to do |f|
142
+ f.html { render template: openstax_rescue_config.html_error_template_path,
143
+ layout: openstax_rescue_config.html_error_template_layout_name,
144
+ status: exception_proxy.status }
145
+ f.json { render json: { error_id: exception_proxy.error_id }
146
+ status: exception_proxy.status }
147
+ f.all { render nothing: true, status: exception_proxy.status }
148
+ end
149
+ end
150
+
151
+ # Just override this method in your own controller if you wish
152
+ ```
153
+
154
+ You will readily note that for HTML response, there is an error template rendered from within the gem. See below for overriding these default views.
155
+
156
+ ## Override the views
157
+
158
+ You can either declare your own template path variables:
159
+
160
+ ```ruby
161
+ OpenStax::RescueFrom.configure do |config|
162
+ config.html_error_template_path = 'my/path'
163
+ config.html_error_template_layout_name = 'my_layout'
164
+ end
165
+ ```
166
+
167
+ or, you can generate the views into the default path:
168
+
169
+ ```
170
+ $ rails g open_stax:rescue_from:views
171
+ ```
172
+
173
+ ## View helper
174
+
175
+ The gem provides an `openstax_rescue_from_contact_info` view helper that uses `OpenStax::RescueFrom.configuration.contact_name` to provide either just the name, or to link web and email addresses automatically for you.
26
176
 
27
177
  ## Development
28
178
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
179
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
180
 
31
181
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
182
 
33
183
  ## Contributing
34
184
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rescue_from.
36
-
185
+ Bug reports and pull requests are welcome on GitHub at https://github.com/openstax/rescue_from.
37
186
 
38
187
  ## License
39
188
 
40
189
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
41
-
data/Rakefile CHANGED
@@ -4,3 +4,7 @@ require "rspec/core/rake_task"
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
6
  task :default => :spec
7
+
8
+ Bundler::GemHelper.install_tasks
9
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
10
+ load 'rails/tasks/engine.rake'
@@ -0,0 +1,4 @@
1
+ <h3><%= @message %></h3>
2
+
3
+ <p>We're sorry this <%= @code %> error occurred. If you need help, please contact <%= openstax_rescue_from_contact_info %><%= " and reference error #{@error_id}" if @error_id %>.</p>
4
+
@@ -0,0 +1,13 @@
1
+ require 'rails/generators'
2
+
3
+ module OpenStax
4
+ module RescueFrom
5
+ class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("../templates", __FILE__)
7
+
8
+ def copy_initializer
9
+ copy_file "rescue_from.rb", "config/initializers/rescue_from.rb"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,51 @@
1
+ require 'openstax_rescue_from'
2
+
3
+ OpenStax::RescueFrom.configure do |config|
4
+ config.raise_exceptions = ![false, 'false'].include?(ENV['RAISE_EXCEPTIONS']) ||
5
+ Rails.application.config.consider_all_requests_local
6
+
7
+ # config.app_name = ENV['APP_NAME']
8
+ # config.app_env = ENV['APP_ENV']
9
+ # config.contact_name = ENV['EXCEPTION_CONTACT_NAME']
10
+
11
+ # config.notifier = ExceptionNotifier
12
+
13
+ # config.html_error_template_path = 'errors/any'
14
+ # config.html_error_template_layout_name = 'application'
15
+
16
+ # config.email_prefix = "[#{app_name}] (#{app_env}) "
17
+ # config.sender_address = ENV['EXCEPTION_SENDER']
18
+ # config.exception_recipients = ENV['EXCEPTION_RECIPIENTS']
19
+ end
20
+
21
+ # OpenStax::RescueFrom#register_exception default options:
22
+ #
23
+ # { notify: true,
24
+ # status: :internal_server_error,
25
+ # extras: ->(exception) { {} } }
26
+ #
27
+ # NOTE: Any unregistered exceptions rescued during run-time
28
+ # will be registered with RescueFrom with the above options
29
+
30
+ # OpenStax::RescueFrom.register_exception('SecurityTransgression',
31
+ # notify: false,
32
+ # status: :forbidden)
33
+ #
34
+ # OpenStax::RescueFrom.register_exception(ActiveRecord::NotFound,
35
+ # notify: false,
36
+ # status: :not_found)
37
+ #
38
+ # OpenStax::RescueFrom.register_exception('OAuth2::Error',
39
+ # notify: true,
40
+ # extras: ->(exception) {
41
+ # { headers: exception.response.headers,
42
+ # status: exception.response.status,
43
+ # body: exception.response.body }
44
+ #
45
+ # OpenStax::RescueFrom.translate_status_codes({
46
+ # forbidden: "You are not allowed to access this.",
47
+ # :not_found => "We couldn't find what you asked for.",
48
+ # })
49
+ #
50
+ # Default:
51
+ # - internal_server_error: "Sorry, #{OpenStax::RescueFrom.configuration.app_name} had some unexpected trouble with your request."
@@ -0,0 +1,13 @@
1
+ require 'rails/generators'
2
+
3
+ module OpenStax
4
+ module RescueFrom
5
+ class ViewsGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("../../../../../../app/views", __FILE__)
7
+
8
+ def copy_views
9
+ copy_file "errors/any.html.erb", "app/views/errors/any.html.erb"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,11 +1,36 @@
1
+ require 'exception_notification'
2
+
1
3
  module OpenStax
2
4
  module RescueFrom
3
5
  class Configuration
4
6
 
5
- # attr_accessor, attr_reader, attr_writers for variables
7
+ attr_accessor :raise_exceptions, :notifier, :html_error_template_path,
8
+ :html_error_template_layout_name, :app_name, :app_env, :contact_name,
9
+ :email_prefix, :sender_address, :exception_recipients
6
10
 
7
11
  def initialize
8
- # set default values for variables
12
+ @raise_exceptions = ![false, 'false'].include?(ENV['RAISE_EXCEPTIONS'])
13
+
14
+ @app_name = ENV['APP_NAME']
15
+ @app_env = ENV['APP_ENV']
16
+ @contact_name = ENV['EXCEPTION_CONTACT_NAME']
17
+
18
+ @notifier = ExceptionNotifier
19
+
20
+ @html_error_template_path = 'errors/any'
21
+ @html_error_template_layout_name = 'application'
22
+
23
+ @sender_address = ENV['EXCEPTION_SENDER']
24
+ @exception_recipients = ENV['EXCEPTION_RECIPIENTS']
25
+ end
26
+
27
+ def email_prefix
28
+ return(@email_prefix) if defined?(@email_prefix) && !@email_prefix.blank?
29
+
30
+ name = app_name.blank? ? nil : "[#{app_name}]"
31
+ env = app_env.blank? ? nil : "(#{app_env}) "
32
+
33
+ @email_prefix = [name, env].compact.join(' ')
9
34
  end
10
35
  end
11
36
  end
@@ -0,0 +1,38 @@
1
+ module OpenStax
2
+ module RescueFrom
3
+ module Controller
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ def use_openstax_exception_rescue
10
+ rescue_from Exception do |exception|
11
+ RescueFrom.perform_rescue(exception, self)
12
+ end
13
+ end
14
+ end
15
+
16
+ def openstax_exception_rescued(proxy)
17
+ @message = proxy.friendly_message
18
+ @code = proxy.status_code
19
+ @error_id = proxy.error_id
20
+
21
+ respond_to do |f|
22
+ f.html { render template: openstax_rescue_config.html_error_template_path,
23
+ layout: openstax_rescue_config.html_error_template_layout_name,
24
+ status: proxy.status }
25
+
26
+ f.json { render json: { error_id: proxy.error_id }, status: proxy.status }
27
+
28
+ f.all { render nothing: true, status: proxy.status }
29
+ end
30
+ end
31
+
32
+ private
33
+ def openstax_rescue_config
34
+ RescueFrom.configuration
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,42 @@
1
+ module OpenStax
2
+ module RescueFrom
3
+ class DefaultExceptions
4
+ def self.pre_register!
5
+ RescueFrom.register_exception(ActiveRecord::RecordNotFound,
6
+ notify: false,
7
+ status: :not_found)
8
+
9
+ RescueFrom.register_exception(ActionController::RoutingError,
10
+ notify: false,
11
+ status: :not_found)
12
+
13
+ RescueFrom.register_exception(ActionController::UnknownController,
14
+ notify: false,
15
+ status: :not_found)
16
+
17
+ RescueFrom.register_exception(ActionController::InvalidAuthenticityToken,
18
+ notify: false,
19
+ status: :unprocessable_entity)
20
+
21
+ RescueFrom.register_exception(AbstractController::ActionNotFound,
22
+ notify: false,
23
+ status: :not_found)
24
+
25
+ RescueFrom.register_exception(ActionView::MissingTemplate,
26
+ notify: false,
27
+ status: :bad_request)
28
+
29
+ RescueFrom.register_exception('SecurityTransgression',
30
+ notify: false,
31
+ status: :forbidden)
32
+
33
+ RescueFrom.register_exception('OAuth2::Error',
34
+ extras: ->(ex) {
35
+ { headers: ex.response.headers,
36
+ status: ex.response.status,
37
+ body: ex.response.body }
38
+ })
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,33 @@
1
+ require 'openstax/rescue_from/default_exceptions'
2
+
3
+ module OpenStax
4
+ module RescueFrom
5
+ class Engine < ::Rails::Engine
6
+ initializer 'openstax.rescue_from.inflection' do
7
+ ActiveSupport::Inflector.inflections do |inflect|
8
+ inflect.acronym 'OpenStax'
9
+ end
10
+ end
11
+
12
+ initializer "openstax.rescue_from.action_controller" do
13
+ ActionController::Base.send :include, Controller
14
+ end
15
+
16
+ initializer "openstax.rescue_from.view_helpers" do
17
+ ActionView::Base.send :include, ViewHelpers
18
+ end
19
+
20
+ initializer "openstax.rescue_from.use_exception_notification_middleware" do
21
+ Rails.application.config.middleware.use ExceptionNotification::Rack, email: {
22
+ email_prefix: RescueFrom.configuration.email_prefix,
23
+ sender_address: RescueFrom.configuration.sender_address,
24
+ exception_recipients: RescueFrom.configuration.exception_recipients
25
+ }
26
+ end
27
+
28
+ initializer "openstax.rescue_from.pre_register_exceptions" do
29
+ OpenStax::RescueFrom::DefaultExceptions.pre_register!
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,22 @@
1
+ module OpenStax
2
+ module RescueFrom
3
+ class ExceptionOptions
4
+ attr_accessor :notify, :status_code, :extras
5
+
6
+ def initialize(options = {})
7
+ options.stringify_keys!
8
+ options = { 'notify' => true,
9
+ 'status' => :internal_server_error,
10
+ 'extras' => ->(exception) { {} } }.merge(options)
11
+
12
+ @notify = options['notify']
13
+ @status_code = options['status']
14
+ @extras = options['extras']
15
+ end
16
+
17
+ def notify?
18
+ @notify
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,55 @@
1
+ module OpenStax
2
+ module RescueFrom
3
+ class ExceptionProxy
4
+ attr_reader :exception
5
+
6
+ def initialize(exception)
7
+ @exception = exception
8
+ end
9
+
10
+ def name
11
+ @name ||= exception.class.name
12
+ end
13
+
14
+ def error_id
15
+ @error_id ||= RescueFrom.generate_id
16
+ end
17
+
18
+ def message
19
+ @message ||= exception.message
20
+ end
21
+
22
+ def friendly_message
23
+ RescueFrom.friendly_message(status)
24
+ end
25
+
26
+ def extras
27
+ @extras ||= RescueFrom.extras_proc(name).call(exception)
28
+ end
29
+
30
+ def cause
31
+ @cause ||= exception.respond_to?(:cause) ? exception.cause : nil
32
+ end
33
+
34
+ def backtrace
35
+ @backtrace ||= cause.blank? ? first_backtrace_line : all_backtrace_lines
36
+ end
37
+
38
+ def all_backtrace_lines
39
+ @all_backtrace_lines ||= exception.backtrace.join("\n")
40
+ end
41
+
42
+ def first_backtrace_line
43
+ @first_backtrace_line ||= exception.backtrace.first
44
+ end
45
+
46
+ def status
47
+ @status ||= RescueFrom.status(name)
48
+ end
49
+
50
+ def status_code
51
+ @status_code ||= RescueFrom.http_code(status)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,28 @@
1
+ module OpenStax
2
+ module RescueFrom
3
+ class Logger
4
+ attr_reader :proxy
5
+
6
+ def initialize(proxy)
7
+ @proxy = proxy
8
+ end
9
+
10
+ def record_system_error!(prefix = "An exception occurred")
11
+ Rails.logger.error("#{prefix}: #{proxy.name} [#{proxy.error_id}] " +
12
+ "<#{proxy.message}> #{proxy.extras}\n\n" +
13
+ "#{proxy.backtrace}")
14
+
15
+ record_system_error_recursively!
16
+ end
17
+
18
+ private
19
+ def record_system_error_recursively!
20
+ if proxy.cause
21
+ RescueFrom.register_exception(proxy.cause.class)
22
+ @proxy = ExceptionProxy.new(proxy.cause)
23
+ record_system_error!("Exception cause")
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,14 @@
1
+ module OpenStax
2
+ module RescueFrom
3
+ class MuteListener
4
+ def openstax_exception_rescued(proxy)
5
+ Rails.logger.warn("MuteListener does nothing after rescuing " +
6
+ "ExceptionProxy#error_id #=> #{proxy.error_id}")
7
+ end
8
+
9
+ def request
10
+ OpenStruct.new(remote_ip: '0.0.0.0')
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,5 +1,5 @@
1
1
  module OpenStax
2
2
  module RescueFrom
3
- VERSION = "0.0.1"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
@@ -0,0 +1,18 @@
1
+ module OpenStax
2
+ module RescueFrom
3
+ module ViewHelpers
4
+ def openstax_rescue_from_contact_info
5
+ info = OpenStax::RescueFrom.configuration.contact_name
6
+
7
+ if info.match(/\S+@\S+\.\w{2,4}/)
8
+ mail_to info
9
+ elsif info.match(/\S+\.\w{2,4}\z/)
10
+ info = info.match(/\Ahttps?:\/\//) ? info : "http://#{info}"
11
+ link_to info, info
12
+ else
13
+ info
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,124 @@
1
+ require 'openstax/rescue_from/exception_options'
2
+ require 'openstax/rescue_from/controller'
3
+ require 'openstax/rescue_from/view_helpers'
4
+ require 'openstax/rescue_from/configuration'
5
+
6
+ module OpenStax
7
+ module RescueFrom
8
+ class << self
9
+ def perform_rescue(exception, listener = MuteListener.new)
10
+ unless registered_exceptions.keys.include?(exception.class.name)
11
+ register_exception(exception.class)
12
+ end
13
+
14
+ proxy = ExceptionProxy.new(exception)
15
+ log_system_error(proxy)
16
+ send_notifying_exceptions(proxy, listener)
17
+ finish_exception_rescue(proxy, listener)
18
+ end
19
+
20
+ def register_exception(exception, options = {})
21
+ name = exception.is_a?(String) ? exception : exception.name
22
+ @@registered_exceptions ||= {}
23
+ @@registered_exceptions[name] = ExceptionOptions.new(options)
24
+ end
25
+
26
+ def translate_status_codes(map = {})
27
+ map.each do |k, v|
28
+ friendly_status_messages[k] = v
29
+ end
30
+ end
31
+
32
+ def registered_exceptions
33
+ @@registered_exceptions.dup
34
+ end
35
+
36
+ def non_notifying_exceptions
37
+ @@registered_exceptions.reject { |_, v| v.notify? }.keys
38
+ end
39
+
40
+ def notifying_exceptions
41
+ @@registered_exceptions.select { |_, v| v.notify? }.keys
42
+ end
43
+
44
+ def friendly_message(status)
45
+ friendly_status_messages[status] || default_friendly_message
46
+ end
47
+
48
+ def notifies_for?(exception_name)
49
+ notifying_exceptions.include?(exception_name)
50
+ end
51
+
52
+ def status(exception_name)
53
+ @@registered_exceptions[exception_name].status_code
54
+ end
55
+
56
+ def http_code(status)
57
+ Rack::Utils.status_code(status)
58
+ end
59
+
60
+ def extras_proc(exception_name)
61
+ @@registered_exceptions[exception_name].extras
62
+ end
63
+
64
+ def generate_id
65
+ "%06d#{SecureRandom.random_number(10**6)}"
66
+ end
67
+
68
+ def configure
69
+ yield configuration
70
+ end
71
+
72
+ def configuration
73
+ @configuration ||= Configuration.new
74
+ end
75
+
76
+ private
77
+ def friendly_status_messages
78
+ @@friendly_status_messages ||= {
79
+ internal_server_error: default_friendly_message
80
+ }
81
+ end
82
+
83
+ def default_friendly_message
84
+ "Sorry, #{configuration.app_name} had some unexpected trouble with your request."
85
+ end
86
+
87
+ def resolve_ip(ip)
88
+ Resolv.getname(ip) rescue 'unknown'
89
+ end
90
+
91
+ def log_system_error(proxy)
92
+ logger = Logger.new(proxy)
93
+ logger.record_system_error!
94
+ end
95
+
96
+ def send_notifying_exceptions(proxy, listener)
97
+ if notifies_for?(proxy.name)
98
+ configuration.notifier.notify_exception(
99
+ proxy.exception,
100
+ env: listener.request.env,
101
+ data: {
102
+ error_id: proxy.error_id,
103
+ :class => proxy.name,
104
+ message: proxy.message,
105
+ first_line_of_backtrace: proxy.first_backtrace_line,
106
+ cause: proxy.cause,
107
+ dns_name: resolve_ip(listener.request.remote_ip),
108
+ extras: proxy.extras
109
+ },
110
+ sections: %w(data request session environment backtrace)
111
+ )
112
+ end
113
+ end
114
+
115
+ def finish_exception_rescue(proxy, listener)
116
+ if configuration.raise_exceptions
117
+ raise proxy.exception
118
+ else
119
+ listener.openstax_exception_rescued(proxy)
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -1,37 +1,11 @@
1
- ActiveSupport::Inflector.inflections do |inflect|
2
- inflect.acronym 'OpenStax'
3
- end
4
-
5
- require "openstax/rescue_from/configuration"
6
- require "openstax/rescue_from/version"
7
-
8
- module OpenStax
9
- module RescueFrom
1
+ require 'openstax/rescue_from'
2
+ require 'openstax/rescue_from/version'
3
+ require 'openstax/rescue_from/engine'
10
4
 
11
- class << self
5
+ require 'openstax/rescue_from/mute_listener'
6
+ require 'openstax/rescue_from/logger'
12
7
 
13
- ###########################################################################
14
- #
15
- # Configuration machinery.
16
- #
17
- # To configure OpenStax RescueFrom, put the following code in your
18
- # application's initialization logic
19
- # (eg. in the config/initializers in a Rails app)
20
- #
21
- # OpenStax::RescueFrom.configure do |config|
22
- # config.<parameter name> = <parameter value>
23
- # ...
24
- # end
25
- #
8
+ require 'openstax/rescue_from/exception_proxy'
26
9
 
27
- def configure
28
- yield configuration
29
- end
30
-
31
- def configuration
32
- @configuration ||= Configuration.new
33
- end
34
-
35
- end
36
- end
10
+ module OpenStax
37
11
  end
@@ -6,8 +6,8 @@ require 'openstax/rescue_from/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "openstax_rescue_from"
8
8
  spec.version = OpenStax::RescueFrom::VERSION
9
- spec.authors = ["JP Slavinsky"]
10
- spec.email = ["jps@kindlinglabs.com"]
9
+ spec.authors = ["JP Slavinsky", "Joe Sak"]
10
+ spec.email = ["jps@kindlinglabs.com", "joe@avant-gardelabs.com"]
11
11
 
12
12
  spec.summary = %q{Common exception `rescue_from` handling for OpenStax sites.}
13
13
  spec.homepage = "https://github.com/openstax/rescue_from"
@@ -18,7 +18,14 @@ Gem::Specification.new do |spec|
18
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency "rails", '>= 3.1', '< 5.0'
22
+ spec.add_dependency "exception_notification", '>= 4.1', '< 5.0'
23
+
24
+ spec.add_development_dependency "pg", '~> 0.18.3'
21
25
  spec.add_development_dependency "bundler", "~> 1.10"
22
26
  spec.add_development_dependency "rake", "~> 10.0"
23
- spec.add_development_dependency "rspec"
27
+ spec.add_development_dependency "rspec-rails", '~> 3.3.3'
28
+ spec.add_development_dependency "pry-nav", '~> 0.2.4'
29
+ spec.add_development_dependency "pry-rails", '~> 0.3.4'
30
+ spec.add_development_dependency "database_cleaner", '~> 1.5.0'
24
31
  end
metadata CHANGED
@@ -1,77 +1,190 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openstax_rescue_from
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - JP Slavinsky
8
+ - Joe Sak
8
9
  autorequire:
9
10
  bindir: exe
10
11
  cert_chain: []
11
- date: 2015-09-17 00:00:00.000000000 Z
12
+ date: 2015-10-02 00:00:00.000000000 Z
12
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ! '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '3.1'
21
+ - - <
22
+ - !ruby/object:Gem::Version
23
+ version: '5.0'
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '3.1'
31
+ - - <
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ - !ruby/object:Gem::Dependency
35
+ name: exception_notification
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '4.1'
41
+ - - <
42
+ - !ruby/object:Gem::Version
43
+ version: '5.0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ! '>='
49
+ - !ruby/object:Gem::Version
50
+ version: '4.1'
51
+ - - <
52
+ - !ruby/object:Gem::Version
53
+ version: '5.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: pg
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ version: 0.18.3
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ~>
66
+ - !ruby/object:Gem::Version
67
+ version: 0.18.3
13
68
  - !ruby/object:Gem::Dependency
14
69
  name: bundler
15
70
  requirement: !ruby/object:Gem::Requirement
16
71
  requirements:
17
- - - "~>"
72
+ - - ~>
18
73
  - !ruby/object:Gem::Version
19
74
  version: '1.10'
20
75
  type: :development
21
76
  prerelease: false
22
77
  version_requirements: !ruby/object:Gem::Requirement
23
78
  requirements:
24
- - - "~>"
79
+ - - ~>
25
80
  - !ruby/object:Gem::Version
26
81
  version: '1.10'
27
82
  - !ruby/object:Gem::Dependency
28
83
  name: rake
29
84
  requirement: !ruby/object:Gem::Requirement
30
85
  requirements:
31
- - - "~>"
86
+ - - ~>
32
87
  - !ruby/object:Gem::Version
33
88
  version: '10.0'
34
89
  type: :development
35
90
  prerelease: false
36
91
  version_requirements: !ruby/object:Gem::Requirement
37
92
  requirements:
38
- - - "~>"
93
+ - - ~>
39
94
  - !ruby/object:Gem::Version
40
95
  version: '10.0'
41
96
  - !ruby/object:Gem::Dependency
42
- name: rspec
97
+ name: rspec-rails
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ~>
101
+ - !ruby/object:Gem::Version
102
+ version: 3.3.3
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 3.3.3
110
+ - !ruby/object:Gem::Dependency
111
+ name: pry-nav
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ~>
115
+ - !ruby/object:Gem::Version
116
+ version: 0.2.4
117
+ type: :development
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ~>
122
+ - !ruby/object:Gem::Version
123
+ version: 0.2.4
124
+ - !ruby/object:Gem::Dependency
125
+ name: pry-rails
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ~>
129
+ - !ruby/object:Gem::Version
130
+ version: 0.3.4
131
+ type: :development
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ~>
136
+ - !ruby/object:Gem::Version
137
+ version: 0.3.4
138
+ - !ruby/object:Gem::Dependency
139
+ name: database_cleaner
43
140
  requirement: !ruby/object:Gem::Requirement
44
141
  requirements:
45
- - - ">="
142
+ - - ~>
46
143
  - !ruby/object:Gem::Version
47
- version: '0'
144
+ version: 1.5.0
48
145
  type: :development
49
146
  prerelease: false
50
147
  version_requirements: !ruby/object:Gem::Requirement
51
148
  requirements:
52
- - - ">="
149
+ - - ~>
53
150
  - !ruby/object:Gem::Version
54
- version: '0'
151
+ version: 1.5.0
55
152
  description:
56
153
  email:
57
154
  - jps@kindlinglabs.com
155
+ - joe@avant-gardelabs.com
58
156
  executables: []
59
157
  extensions: []
60
158
  extra_rdoc_files: []
61
159
  files:
62
- - ".gitignore"
63
- - ".rspec"
64
- - ".travis.yml"
160
+ - .gitignore
161
+ - .rspec
162
+ - .ruby-gemset
163
+ - .ruby-version
164
+ - .travis.yml
65
165
  - Gemfile
66
166
  - LICENSE.txt
67
167
  - README.md
68
168
  - Rakefile
169
+ - app/views/errors/any.html.erb
69
170
  - bin/console
70
171
  - bin/setup
172
+ - lib/generators/open_stax/rescue_from/install/install_generator.rb
173
+ - lib/generators/open_stax/rescue_from/install/templates/rescue_from.rb
174
+ - lib/generators/open_stax/rescue_from/views/views_generator.rb
175
+ - lib/openstax/rescue_from.rb
71
176
  - lib/openstax/rescue_from/configuration.rb
177
+ - lib/openstax/rescue_from/controller.rb
178
+ - lib/openstax/rescue_from/default_exceptions.rb
179
+ - lib/openstax/rescue_from/engine.rb
180
+ - lib/openstax/rescue_from/exception_options.rb
181
+ - lib/openstax/rescue_from/exception_proxy.rb
182
+ - lib/openstax/rescue_from/logger.rb
183
+ - lib/openstax/rescue_from/mute_listener.rb
72
184
  - lib/openstax/rescue_from/version.rb
185
+ - lib/openstax/rescue_from/view_helpers.rb
73
186
  - lib/openstax_rescue_from.rb
74
- - rescue_from.gemspec
187
+ - openstax_rescue_from.gemspec
75
188
  homepage: https://github.com/openstax/rescue_from
76
189
  licenses:
77
190
  - MIT
@@ -82,17 +195,17 @@ require_paths:
82
195
  - lib
83
196
  required_ruby_version: !ruby/object:Gem::Requirement
84
197
  requirements:
85
- - - ">="
198
+ - - ! '>='
86
199
  - !ruby/object:Gem::Version
87
200
  version: '0'
88
201
  required_rubygems_version: !ruby/object:Gem::Requirement
89
202
  requirements:
90
- - - ">="
203
+ - - ! '>='
91
204
  - !ruby/object:Gem::Version
92
205
  version: '0'
93
206
  requirements: []
94
207
  rubyforge_project:
95
- rubygems_version: 2.4.8
208
+ rubygems_version: 2.4.6
96
209
  signing_key:
97
210
  specification_version: 4
98
211
  summary: Common exception `rescue_from` handling for OpenStax sites.