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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +37 -0
- data/app/assets/javascripts/softwear/application.js +13 -0
- data/app/assets/javascripts/softwear/error_utils.js.coffee +82 -0
- data/app/assets/javascripts/softwear/modals.js.coffee +171 -0
- data/app/assets/stylesheets/softwear/application.css +33 -0
- data/app/controllers/softwear/application_controller.rb +4 -0
- data/app/controllers/softwear/error_reports_controller.rb +37 -0
- data/app/helpers/softwear/application_helper.rb +4 -0
- data/app/helpers/softwear/emails_helper.rb +9 -0
- data/app/mailers/error_report_mailer.rb +53 -0
- data/app/views/error_report_mailer/send_report.html.erb +30 -0
- data/app/views/layouts/softwear/application.html.erb +14 -0
- data/app/views/softwear/errors/_error.html.erb +35 -0
- data/app/views/softwear/errors/internal_server_error.html.erb +6 -0
- data/app/views/softwear/errors/internal_server_error.js.erb +10 -0
- data/bin/rails +12 -0
- data/config/routes.rb +3 -0
- data/lib/softwear/auth/belongs_to_user.rb +43 -0
- data/lib/softwear/auth/controller.rb +43 -0
- data/lib/softwear/auth/helper.rb +35 -0
- data/lib/softwear/auth/model.rb +16 -0
- data/lib/softwear/auth/spec.rb +62 -0
- data/lib/softwear/auth/standard_model.rb +498 -0
- data/lib/softwear/auth/stubbed_model.rb +130 -0
- data/lib/softwear/auth/token_authentication.rb +72 -0
- data/lib/softwear/engine.rb +5 -0
- data/lib/softwear/error_catcher.rb +65 -0
- data/lib/softwear/library/api_controller.rb +169 -0
- data/lib/softwear/library/capistrano.rb +94 -0
- data/lib/softwear/library/controller_authentication.rb +145 -0
- data/lib/softwear/library/enqueue.rb +87 -0
- data/lib/softwear/library/spec.rb +127 -0
- data/lib/softwear/library/tcp_server.rb +107 -0
- data/lib/softwear/version.rb +3 -0
- data/lib/softwear.rb +107 -0
- 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,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,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,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,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
|