softwear 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +37 -0
  4. data/app/assets/javascripts/softwear/application.js +13 -0
  5. data/app/assets/javascripts/softwear/error_utils.js.coffee +82 -0
  6. data/app/assets/javascripts/softwear/modals.js.coffee +171 -0
  7. data/app/assets/stylesheets/softwear/application.css +33 -0
  8. data/app/controllers/softwear/application_controller.rb +4 -0
  9. data/app/controllers/softwear/error_reports_controller.rb +37 -0
  10. data/app/helpers/softwear/application_helper.rb +4 -0
  11. data/app/helpers/softwear/emails_helper.rb +9 -0
  12. data/app/mailers/error_report_mailer.rb +53 -0
  13. data/app/views/error_report_mailer/send_report.html.erb +30 -0
  14. data/app/views/layouts/softwear/application.html.erb +14 -0
  15. data/app/views/softwear/errors/_error.html.erb +35 -0
  16. data/app/views/softwear/errors/internal_server_error.html.erb +6 -0
  17. data/app/views/softwear/errors/internal_server_error.js.erb +10 -0
  18. data/bin/rails +12 -0
  19. data/config/routes.rb +3 -0
  20. data/lib/softwear/auth/belongs_to_user.rb +43 -0
  21. data/lib/softwear/auth/controller.rb +43 -0
  22. data/lib/softwear/auth/helper.rb +35 -0
  23. data/lib/softwear/auth/model.rb +16 -0
  24. data/lib/softwear/auth/spec.rb +62 -0
  25. data/lib/softwear/auth/standard_model.rb +498 -0
  26. data/lib/softwear/auth/stubbed_model.rb +130 -0
  27. data/lib/softwear/auth/token_authentication.rb +72 -0
  28. data/lib/softwear/engine.rb +5 -0
  29. data/lib/softwear/error_catcher.rb +65 -0
  30. data/lib/softwear/library/api_controller.rb +169 -0
  31. data/lib/softwear/library/capistrano.rb +94 -0
  32. data/lib/softwear/library/controller_authentication.rb +145 -0
  33. data/lib/softwear/library/enqueue.rb +87 -0
  34. data/lib/softwear/library/spec.rb +127 -0
  35. data/lib/softwear/library/tcp_server.rb +107 -0
  36. data/lib/softwear/version.rb +3 -0
  37. data/lib/softwear.rb +107 -0
  38. metadata +172 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d715e0759e33a014c97ab25bdd01db678ab666d3
4
+ data.tar.gz: 66ad37169e8051c909ca91c326dba79f1fb20bb3
5
+ SHA512:
6
+ metadata.gz: 4100ed66d9ea3b8c838efd51d85a33fe9c9fba334b02145e12003329d8b503c27476b7831cc8e8ba38a60ca40344a9f6a24252701cac8448e55d506c75587fb5
7
+ data.tar.gz: aa8d8df330bb7564b5a0203758c67024bfa62f65b644633e9f7d9a18d45769c147693c772be87c8af7e3329aeb6482ccf8ac6967075d9aa8dcdce6a852ba0083
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2016 Stefan Gale
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Softwear'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,82 @@
1
+ # Handy little module for ajax error handling!
2
+ # Doesn't actually do the ajaxing for you; just
3
+ # adds and removes error content from the page.
4
+ @ErrorHandler = (resourceName, $form, resourceId) ->
5
+ handler = {}
6
+ capitalize = (str) -> (str.charAt(0).toUpperCase() + str.substr(1)).replace('_id', '').replace('_', ' ')
7
+ contains = (array, thing) ->
8
+ return true if entry == thing for entry in array
9
+ false
10
+ getParamName = (field) ->
11
+ if resourceName is null
12
+ field
13
+ else
14
+ if resourceId
15
+ "#{resourceName}[#{resourceId}][#{field}]"
16
+ else
17
+ "#{resourceName}[#{field}]"
18
+ findFieldElementFor = (field) ->
19
+ $field = $form.find("*[name^='#{getParamName(field)}']")
20
+ $field = $form.find("*[name^='#{getParamName(field.replace('_id', ''))}']") if $field.length == 0
21
+ $field = $form.find("*[name^='#{getParamName(field + '_id')}']") if $field.length == 0
22
+ $field
23
+
24
+ handler.errorFields = []
25
+
26
+ handler.handleErrors = (errors, modal) ->
27
+ handler.clear() if handler.errorFields.length > 0
28
+ # Add modal
29
+ $modal = null
30
+ unless modal is null
31
+ $modal = $(modal)
32
+ $('body').append $modal
33
+ $modal.on 'hidden.bs.modal', (e) -> $modal.remove()
34
+ # Mark fields
35
+ for field, fieldErrors of errors
36
+ continue if fieldErrors.length == 0
37
+ handler.errorFields.push(field)
38
+ # Grab the input field element
39
+ $field = findFieldElementFor field
40
+
41
+ if $field.length == 0
42
+ console.log "Couldn't find field #{field} (name #{getParamName(field)})"
43
+ continue
44
+
45
+ # Create the error message div
46
+ $errorMsgDiv = $ '<div/>',
47
+ class: 'error'
48
+ for: getParamName(field)
49
+
50
+ # Place it before the input field
51
+ $field.before $errorMsgDiv
52
+
53
+ # Wrap the input field to make it red
54
+ $field.wrap $('<div/>', class: 'field_with_errors') unless $field.data('no-wrap')
55
+
56
+ # Populate error message div with messages
57
+ for error in fieldErrors
58
+ $errorMsgDiv.append $ '<p/>',
59
+ class: 'text-danger'
60
+ text: "#{capitalize field} #{error}"
61
+
62
+ # Show the modal
63
+ $modal.modal 'show' unless $modal is null
64
+
65
+ handler.clear = () ->
66
+ for field in handler.errorFields
67
+ $field = findFieldElementFor field
68
+ $errorMsgDiv = $form.find(".error[for='#{getParamName(field)}']")
69
+ $errorMsgDiv.remove()
70
+ $field.unwrap() if $field.parent().hasClass('field_with_errors') and not $field.data('no-wrap')
71
+ handler.errorFields = []
72
+
73
+ return handler
74
+
75
+ @errorHandlerFrom = (element, resourceName, $form, resourceId) ->
76
+ $element = $(element)
77
+ handler = $element.data 'error-handler'
78
+ if handler is undefined
79
+ handler = ErrorHandler(resourceName, $form, resourceId)
80
+ $element.data 'error-handler', handler
81
+
82
+ handler
@@ -0,0 +1,171 @@
1
+ $(document).ready ->
2
+ $contentModal = $('#contentModal')
3
+
4
+ $contentModal.DEFAULTS
5
+
6
+ storeClassFor = ($elem) ->
7
+ $elem.data 'original-class', $elem.attr('class')
8
+ retrieveClassFor = ($elem) ->
9
+ unless typeof $elem.data('original-class') is 'undefined'
10
+ $elem.attr 'class', $elem.data('original-class')
11
+
12
+ storeClassFor $contentModal
13
+ $('#contentModal *').each (index) ->
14
+ storeClassFor $(this)
15
+
16
+ # When the content modal is closed, clean up any alterations
17
+ # to classes/content.
18
+ $contentModal.on 'hidden.bs.modal', ->
19
+ retrieveClassFor $contentModal
20
+ $('#contentModal *').each ->
21
+ retrieveClassFor $(this)
22
+ $contentModal.find('.modal-content-area').empty()
23
+ $contentModal.data 'open', false
24
+
25
+ $contentModal.on 'show.bs.modal', ->
26
+ $contentModal.data 'open', true
27
+
28
+ ##
29
+ # Quick and easy way to show the content modal!
30
+ #
31
+ # Valid options include: 'title', 'body', 'footer', and 'force'
32
+ #
33
+ # Example (in coffeescript):
34
+ # ===============================
35
+ # setupContentModal ($contentModal) ->
36
+ # $contentModal.find('.modal-dialog').addClass 'modal-lg'
37
+ # showContentModal
38
+ # title: $('<strong>Test Content Modal!</strong>')
39
+ # body: "This is a large modal! These options allow strings or jQueries."
40
+ # footer: $('<button data-dismiss="modal">Close</button>')
41
+ # backdrop: 'static'
42
+ # ===============================
43
+ #
44
+ # TODO backdrop is permanent until new page/reload - fix that.
45
+ #
46
+ # Calling setupContentModal is not neccessary if you are fine
47
+ # with the default look of the contentModal. However, if you
48
+ # want to add classes to the modal's innards, I recommend you
49
+ # make those adjustments within setupContentModal to avoid
50
+ # potential conflicts if the modal is already open.
51
+ #
52
+ # By default, calling showContentModal will close the content
53
+ # modal if it is already open. If for some reason you don't
54
+ # want that to happen, you can also pass force: false.
55
+ ##
56
+ @setupContentModal = (setupFunc) ->
57
+ $contentModal = $('#contentModal')
58
+ wasOpen = false
59
+ doSetup = ->
60
+ $contentModal.off 'hidden.bs.modal', doSetup if wasOpen
61
+ setupFunc($contentModal)
62
+
63
+ if $contentModal.data('open')
64
+ wasOpen = true
65
+ $contentModal.on 'hidden.bs.modal', doSetup
66
+ else
67
+ doSetup()
68
+
69
+ @showContentModal = (options) ->
70
+ options.force = true unless options.force is false
71
+ $contentModal = $('#contentModal')
72
+
73
+ wasOpen = false
74
+ showIt = ->
75
+ $contentModal.off 'hidden.bs.modal', showIt if wasOpen
76
+ setSection = ($section, option) ->
77
+ if typeof option is 'string'
78
+ $section.text option
79
+ else
80
+ $section.append option
81
+
82
+ setSection $('#contentTitle'), options.title
83
+ setSection $('#contentBody'), options.body
84
+ setSection $('#contentFooter'), options.footer
85
+
86
+ options.title = null
87
+ options.body = null
88
+ options.footer = null
89
+
90
+ $contentModal.modal options
91
+ options.then($contentModal) if options.then
92
+
93
+ if $contentModal.data('open')
94
+ if options.force is true
95
+ wasOpen = true
96
+ $contentModal.on 'hidden.bs.modal', showIt
97
+ $contentModal.modal 'hide'
98
+ else
99
+ showIt()
100
+
101
+ @hideContentModal = -> $('#contentModal').modal 'hide'
102
+
103
+ # Call this to invoke an error modal, sort of like alert
104
+ # body parameter is optional, title will default to "Error"
105
+ @errorModal = (body, options) ->
106
+ options = {} unless typeof options is 'object'
107
+
108
+ options.title ||= 'Error'
109
+ options.body ||= body
110
+ options.footer ||= $('<button class="btn btn-danger" data-dismiss="modal">OK</button>')
111
+
112
+ setupContentModal ($contentModal) ->
113
+ $contentModal.find('.modal-content').addClass 'modal-content-error'
114
+ $contentModal.find('.modal-body').addClass 'centered'
115
+ showContentModal options
116
+
117
+ # Opens a modal that looks just like the flash modal when
118
+ # the flash contains a success message.
119
+ @successModal = (titleOrBody, body, setup) ->
120
+ title =
121
+ if body
122
+ titleOrBody
123
+ else
124
+ body = titleOrBody
125
+ "Success"
126
+
127
+ setupContentModal ($contentModal) ->
128
+ $contentModal.find('.modal-content').addClass 'modal-content-success'
129
+ $contentModal.find('.modal-body').addClass 'centered'
130
+ setup($contentModal) if setup
131
+ showContentModal
132
+ title: title
133
+ body: body
134
+ footer: $("<button class='btn btn-default' data-dismiss='modal'>OK</button>")
135
+
136
+ # Modal alternative to confirm() except you pass a function
137
+ # rather than call as a conditional.
138
+ #
139
+ # With the callback, you can either pass a parameterless
140
+ # function that will only be called when 'confirm' is clicked,
141
+ # or a single-parameter function where the parameter will
142
+ # be true or false depending on the user's response.
143
+ @confirmModal = (question, callback) ->
144
+ $modal = $('#contentModal')
145
+
146
+ $yesBtn = $ '<a class="btn btn-primary" id="modal-confirm-btn">Confirm</a>'
147
+ $noBtn = $ '<a class="btn btn-default" id="modal-cancel-btn">Cancel</a>'
148
+
149
+ $footer = $('#contentFooter')
150
+ $footer.children().remove()
151
+ $footer.append $yesBtn
152
+ $footer.append $noBtn
153
+
154
+ $yesBtn.click ->
155
+ $modal.modal 'hide'
156
+ if callback.length is 0
157
+ callback()
158
+ else
159
+ callback(true)
160
+ $noBtn.click ->
161
+ $modal.modal 'hide'
162
+ if callback.length >= 1
163
+ callback(false)
164
+
165
+ setupContentModal ($contentModal) ->
166
+ $contentModal.find('.modal-dialog').addClass 'modal-sm'
167
+ $contentModal.find('.modal-body').addClass 'centered'
168
+ showContentModal
169
+ title: 'Confirm'
170
+ body: question
171
+ footer: $footer
@@ -0,0 +1,33 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
16
+
17
+ .full-content-center{
18
+ width: 100%;
19
+ max-width: 500px;
20
+ margin: 5% auto;
21
+ text-align: center;
22
+ }
23
+
24
+ .box-info{
25
+ position:relative;
26
+ padding: 15px;
27
+ background: #fff;
28
+ color: #5b5b5b;
29
+ margin-bottom: 20px;
30
+ -webkit-transition:All 0.4s ease;
31
+ -moz-transition:All 0.4s ease;
32
+ -o-transition:All 0.4s ease;
33
+ }
@@ -0,0 +1,4 @@
1
+ module Softwear
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,37 @@
1
+ module Softwear
2
+ class ErrorReportsController < ApplicationController
3
+ skip_before_filter :authenticate_user!
4
+
5
+ helper Softwear::Engine.helpers do
6
+ def method_missing(name, *args, &block)
7
+ if main_app.respond_to?(name)
8
+ main_app.send(name, *args, &block)
9
+ else
10
+ super
11
+ end
12
+ end
13
+ end
14
+
15
+ def email_report
16
+ if current_user
17
+ user = current_user
18
+ else
19
+ begin
20
+ user = User.find(params[:user_id]) unless params[:user_id].blank?
21
+ rescue StandardError => _e
22
+ end
23
+ end
24
+
25
+ ErrorReportMailer.send_report(user, params).deliver
26
+ flash[:success] = 'Sent error report. Sorry about that.'
27
+
28
+ if user
29
+ redirect_to '/'
30
+ elsif params[:order_id] && (key = Order.where(id: params[:order_id]).pluck(:customer_key).first)
31
+ redirect_to customer_order_path(key)
32
+ else
33
+ render inline: "<%= flash[:success] %>"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,4 @@
1
+ module Softwear
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,9 @@
1
+ module Softwear
2
+ module EmailsHelper
3
+ def backtrace_is_from_app?(line)
4
+ !(line.include?('/gems/') || /^kernel\// =~ line || line.include?('/vendor_ruby/'))
5
+ end
6
+
7
+ extend self
8
+ end
9
+ end
@@ -0,0 +1,53 @@
1
+ class ErrorReportMailer < ActionMailer::Base
2
+ default to: 'devteam@annarbortees.com'
3
+
4
+ def send_report(user, params)
5
+ @order = Order.find_by(id: params[:order_id])
6
+ @user = user || User.find_by(id: params[:user_id])
7
+
8
+ if @user.nil?
9
+ from_customer = true
10
+
11
+ if @order.nil?
12
+ @user = OpenStruct.new(
13
+ email: 'unknown-user@annarbortees.com',
14
+ full_name: 'Unknown Customer'
15
+ )
16
+ else
17
+ @user = OpenStruct.new(
18
+ email: @order.email,
19
+ full_name: "(Customer) #{@order.full_name}"
20
+ )
21
+ end
22
+ end
23
+
24
+ @error_class = params[:error_class]
25
+ @error_message = params[:error_message]
26
+ @backtrace = params[:backtrace]
27
+ @user_message = params[:user_message]
28
+ @additional_info = params[:additional_info]
29
+
30
+ mail(
31
+ from: from_customer ? 'customer-report@softwearcrm.com' : @user.email,
32
+ reply_to: @user.email,
33
+ to: 'devteam@annarbortees.com',
34
+ subject: "Softwear CRM Error Report From #{@user.full_name}"
35
+ )
36
+ end
37
+
38
+ def auth_server_down(at)
39
+ mail(
40
+ from: 'noreply@softwearcrm.com',
41
+ subject: 'Authentication server is down!',
42
+ body: at.strftime("Lost contact on %m/%d/%Y at %I:%M%p. We're running on cache!")
43
+ )
44
+ end
45
+
46
+ def auth_server_up(at)
47
+ mail(
48
+ from: 'noreply@softwearcrm.com',
49
+ subject: 'Authentication server back up!',
50
+ body: at.strftime("Just got a response at %I:%M%p")
51
+ )
52
+ end
53
+ end
@@ -0,0 +1,30 @@
1
+ <h1> <%= @user.full_name %>'s report: </h1>
2
+ <div>
3
+ <%= @user.email %>:
4
+ </div>
5
+ <p> <%= @user_message %> </p>
6
+ <h1> Error details: </h1>
7
+ <div>
8
+ <%= @error_class %>: <%= @error_message %>
9
+ </div>
10
+ <div>
11
+ <h4>Additional information:</h4>
12
+ <ul>
13
+ <% @additional_info.split("|||").each do |info| %>
14
+ <li><%= info %></li>
15
+ <% end %>
16
+ </ul>
17
+ </div>
18
+ <div>
19
+ <ul>
20
+ <% @backtrace.split("\n").each do |line| %>
21
+ <li>
22
+ <% if Softwear::EmailsHelper.backtrace_is_from_app?(line) %>
23
+ <strong><%= line %></strong><br />
24
+ <% else %>
25
+ <%= line %><br />
26
+ <% end %>
27
+ </li>
28
+ <% end %>
29
+ </ul>
30
+ </div>
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Softwear</title>
5
+ <%= stylesheet_link_tag "softwear/application", media: "all" %>
6
+ <%= javascript_include_tag "softwear/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,35 @@
1
+ <div>
2
+ Fortunately, a report of this error can be sent to the dev team.
3
+ </div>
4
+
5
+ <% if current_user || !Rails.env.production? %>
6
+ <div>
7
+ <%= link_to 'Show error details', '#', id: 'show-error-details-btn', onclick: '$("#error-details").toggle(); return false;', class: 'btn btn-info' %>
8
+ <div id='error-details' style='<%= "display: none;" if Rails.env.production? %>'>
9
+ <p><%= error.class.name %>: <%= error.message %></p>
10
+ <% error.backtrace.each do |line| %>
11
+ <% if backtrace_is_from_app?(line) %>
12
+ <strong><%= line %></strong><br />
13
+ <% else %>
14
+ <%= line %><br />
15
+ <% end %>
16
+ <% end %>
17
+ </div>
18
+ </div>
19
+ <% end %>
20
+
21
+ <%= form_tag softwear.error_report_path, method: :post do %>
22
+ <%= hidden_field_tag 'error_class', error.class.name %>
23
+ <%= hidden_field_tag 'error_message', error.message %>
24
+ <%= hidden_field_tag 'backtrace', error.backtrace.join("\n") %>
25
+ <%= hidden_field_tag 'user_id', current_user.try(:id) %>
26
+ <%= hidden_field_tag 'additional_info', additional_info %>
27
+ <%= hidden_field_tag 'order_id', @order.try(:id) %>
28
+
29
+ <div class='form-group'>
30
+ <%= label_tag 'user_message', 'Describe how you reached this error.' %>
31
+ <%= text_area_tag 'user_message', '', class: 'form-control' %>
32
+ </div>
33
+
34
+ <%= submit_tag 'Send', class: 'btn btn-info' %>
35
+ <% end %>
@@ -0,0 +1,6 @@
1
+ <div class="full-content-center animated fadeInDownBig">
2
+ <div class='box-info'>
3
+ <h2 class='text-center'>You have encountered an error!</h2>
4
+ <%= render 'softwear/errors/error', error: @error, additional_info: @additional_info %>
5
+ </div>
6
+ </div>
@@ -0,0 +1,10 @@
1
+ <% if current_user %>
2
+ setupContentModal(function(modal) {
3
+ modal.find('.modal-content').addClass('modal-content-error');
4
+ modal.find('.modal-body').addClass('centered');
5
+ });
6
+ showContentModal({
7
+ title: 'You have encountered an error!',
8
+ body: $("<%=j render 'softwear/errors/error', error: @error, additional_info: @additional_info %>")
9
+ });
10
+ <% end %>
data/bin/rails ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
3
+
4
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
5
+ ENGINE_PATH = File.expand_path('../../lib/softwear/engine', __FILE__)
6
+
7
+ # Set up gems listed in the Gemfile.
8
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
9
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
10
+
11
+ require 'rails/all'
12
+ require 'rails/engine/commands'
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Softwear::Engine.routes.draw do
2
+ post '/error-report', to: 'error_reports#email_report'
3
+ end
@@ -0,0 +1,43 @@
1
+ module Softwear
2
+ module Auth
3
+ module BelongsToUser
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def belongs_to_user_called(name, options = {})
8
+ foreign_key = "#{name}_id"
9
+
10
+ # Create an anonymous module and include it, so that we can
11
+ # override the generated association methods and call `super`
12
+ # in the method body.
13
+ association_methods = Module.new
14
+ association_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
15
+ def #{name}
16
+ @#{name} ||= User.find(#{name}_id)
17
+ end
18
+
19
+ def #{name}=(new)
20
+ self.#{foreign_key} = new.id
21
+ @#{name} = new
22
+ end
23
+ RUBY
24
+
25
+ self.user_associations ||= []
26
+ user_associations << name.to_sym
27
+
28
+ send(:include, association_methods)
29
+ end
30
+
31
+ def belongs_to_user
32
+ belongs_to_user_called(:user)
33
+ end
34
+ end
35
+
36
+ included do
37
+ extend ClassMethods
38
+
39
+ cattr_accessor :user_associations
40
+ end
41
+ end
42
+ end
43
+ end