softwear 2.0.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.
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