beyond_canvas 0.14.0.pre → 0.16.0.pre
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 +4 -4
- data/README.md +0 -6
- data/app/assets/images/icons/checkbox_checked.svg +1 -0
- data/app/assets/images/icons/checkbox_unchecked.svg +1 -0
- data/app/assets/images/icons/radiobutton_checked.svg +1 -0
- data/app/assets/images/icons/radiobutton_unchecked.svg +1 -0
- data/app/assets/javascripts/beyond_canvas/base.js +248 -87
- data/app/assets/stylesheets/beyond_canvas/base.scss +3 -0
- data/app/assets/stylesheets/beyond_canvas/components/_containers.scss +37 -0
- data/app/assets/stylesheets/beyond_canvas/components/_inputs.scss +47 -1
- data/app/assets/stylesheets/beyond_canvas/settings/_breakpoints.scss +6 -0
- data/app/assets/stylesheets/beyond_canvas/settings/_variables.scss +24 -0
- data/app/assets/stylesheets/beyond_canvas/utilities/_functions.scss +15 -0
- data/app/controllers/beyond_canvas/authentications_controller.rb +62 -0
- data/app/controllers/concerns/beyond_canvas/authentication.rb +24 -0
- data/app/controllers/concerns/beyond_canvas/request_validation.rb +1 -1
- data/app/controllers/concerns/beyond_canvas/resource_management.rb +33 -0
- data/app/form_builders/beyond_canvas/form_builder.rb +65 -8
- data/app/javascript/beyond_canvas/base.js +3 -6
- data/app/javascript/beyond_canvas/initializers/buttons.js +21 -39
- data/app/javascript/beyond_canvas/initializers/flash.js +5 -14
- data/app/javascript/beyond_canvas/initializers/functions.js +41 -0
- data/app/javascript/beyond_canvas/initializers/inputs.js +3 -8
- data/app/views/beyond_canvas/authentications/new.html.erb +18 -0
- data/config/locales/en.yml +4 -0
- data/config/routes.rb +6 -0
- data/lib/beyond_canvas.rb +22 -2
- data/lib/beyond_canvas/configuration.rb +4 -1
- data/lib/beyond_canvas/engine.rb +4 -0
- data/lib/beyond_canvas/models/authentication.rb +66 -0
- data/lib/beyond_canvas/models/shop.rb +28 -0
- data/lib/beyond_canvas/models/utils.rb +55 -0
- data/lib/beyond_canvas/parameter_sanitizer.rb +43 -0
- data/lib/beyond_canvas/rails/routes.rb +21 -0
- data/lib/beyond_canvas/version.rb +1 -1
- data/lib/generators/beyond_canvas/auth_model/auth_model_generator.rb +50 -0
- data/lib/generators/beyond_canvas/auth_model/templates/migration.erb +20 -0
- data/lib/generators/beyond_canvas/auth_model/templates/model.erb +5 -0
- data/lib/generators/beyond_canvas/controller/controller_generator.rb +20 -0
- data/lib/generators/beyond_canvas/controller/templates/controller.erb +37 -0
- data/lib/generators/beyond_canvas/install/install_generator.rb +15 -5
- data/lib/generators/beyond_canvas/install/templates/beyond_canvas.rb.erb +11 -0
- data/lib/generators/beyond_canvas/views/views_generator.rb +19 -0
- metadata +58 -6
@@ -70,6 +70,12 @@ $card-separator-color: rgb(222, 222, 222) !default;
|
|
70
70
|
$card-separator-spacing: 50px !global;
|
71
71
|
$card-title-color: rgb(247, 133, 96) !default;
|
72
72
|
|
73
|
+
// ************************************************************
|
74
|
+
// Containers
|
75
|
+
// ************************************************************
|
76
|
+
|
77
|
+
$container-spacing: 30px !global;
|
78
|
+
|
73
79
|
// ************************************************************
|
74
80
|
// Labels
|
75
81
|
// ************************************************************
|
@@ -84,6 +90,24 @@ $input-border-color: rgb(217, 216, 195) !default;
|
|
84
90
|
$input-border-color-focus: $palette-primary !default;
|
85
91
|
$input-errors-color: $palette-danger !default;
|
86
92
|
|
93
|
+
// ************************************************************
|
94
|
+
// Checkboxes
|
95
|
+
// ************************************************************
|
96
|
+
|
97
|
+
$checkbox-checked-color: #97C344 !default;
|
98
|
+
$checkbox-checked-background: #ffffff !default;
|
99
|
+
$checkbox-unchecked-color: #C2BF9D !default;
|
100
|
+
$checkbox-unchecked-background: #ffffff !default;
|
101
|
+
|
102
|
+
// ************************************************************
|
103
|
+
// Radiobuttons
|
104
|
+
// ************************************************************
|
105
|
+
|
106
|
+
$radio-checked-color: #97C344 !default;
|
107
|
+
$radio-checked-background: #ffffff !default;
|
108
|
+
$radio-unchecked-color: #C2BF9D !default;
|
109
|
+
$radio-unchecked-background: #ffffff !default;
|
110
|
+
|
87
111
|
// ************************************************************
|
88
112
|
// Hints
|
89
113
|
// ************************************************************
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/// Replace `$search` with `$replace` in `$string`
|
2
|
+
/// @author Hugo Giraudel
|
3
|
+
/// @param {String} $string - Initial string
|
4
|
+
/// @param {String} $search - Substring to replace
|
5
|
+
/// @param {String} $replace ('') - New value
|
6
|
+
/// @return {String} - Updated string
|
7
|
+
@function str-replace($string, $search, $replace: '') {
|
8
|
+
$index: str-index($string, $search);
|
9
|
+
|
10
|
+
@if $index {
|
11
|
+
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
|
12
|
+
}
|
13
|
+
|
14
|
+
@return $string;
|
15
|
+
}
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_dependency 'beyond_canvas/application_controller'
|
4
|
+
|
5
|
+
module BeyondCanvas
|
6
|
+
class AuthenticationsController < ApplicationController # :nodoc:
|
7
|
+
layout 'beyond_canvas/public'
|
8
|
+
|
9
|
+
include ::BeyondCanvas::Authentication
|
10
|
+
include ::BeyondCanvas::ResourceManagement
|
11
|
+
|
12
|
+
before_action :validate_app_installation_request!, only: :new
|
13
|
+
|
14
|
+
def new
|
15
|
+
self.resource = resource_class.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def create
|
19
|
+
# Search for the api url. If there is no record it creates a new record.
|
20
|
+
resource_params = new_resource_params
|
21
|
+
self.resource = resource_class.find_or_create_by(beyond_api_url: resource_params[:api_url])
|
22
|
+
# Assign the attributes to the record
|
23
|
+
raise ActiveRecord::RecordNotSaved unless resource.update(resource_params)
|
24
|
+
# Get and save access_token and refresh_token using the authentication code
|
25
|
+
raise BeyondApi::Error if resource.authenticate.is_a?(BeyondApi::Error)
|
26
|
+
|
27
|
+
redirect_to after_create_path
|
28
|
+
rescue ActiveRecord::RecordNotSaved, BeyondApi::Error, StandardError => e
|
29
|
+
logger.error "[BeyondCanvas] #{e.message}".red
|
30
|
+
send "handle_#{e.class.name.split('::').first.underscore}_exception", e
|
31
|
+
end
|
32
|
+
|
33
|
+
def update
|
34
|
+
create
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def new_resource_params
|
40
|
+
send "new_#{resource_name}_params"
|
41
|
+
end
|
42
|
+
|
43
|
+
def after_create_path
|
44
|
+
new_resource_params[:return_url]
|
45
|
+
end
|
46
|
+
|
47
|
+
def handle_active_record_exception(_exception)
|
48
|
+
flash[:error] = t('beyond_canvas.authentications.failure')
|
49
|
+
render :new
|
50
|
+
end
|
51
|
+
|
52
|
+
def handle_beyond_api_exception(_exception)
|
53
|
+
flash[:error] = t('beyond_canvas.authentications.failure')
|
54
|
+
render :new
|
55
|
+
end
|
56
|
+
|
57
|
+
def handle_standard_error_exception(_exception)
|
58
|
+
flash[:error] = t('beyond_canvas.authentications.failure')
|
59
|
+
render :new
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BeyondCanvas
|
4
|
+
module Authentication # :nodoc:
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
AUTH_RESOURCE = BeyondCanvas.auth_model
|
7
|
+
|
8
|
+
class_eval <<-METHODS, __FILE__, __LINE__ + 1
|
9
|
+
def current_#{AUTH_RESOURCE}
|
10
|
+
instance_variable_get("@#{AUTH_RESOURCE}")
|
11
|
+
end
|
12
|
+
|
13
|
+
def new_#{AUTH_RESOURCE}_params
|
14
|
+
beyond_canvas_parameter_sanitizer.sanitize
|
15
|
+
end
|
16
|
+
METHODS
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def beyond_canvas_parameter_sanitizer
|
21
|
+
@beyond_canvas_parameter_sanitizer ||= BeyondCanvas::ParameterSanitizer.new(AUTH_RESOURCE, params)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -31,7 +31,7 @@ module BeyondCanvas
|
|
31
31
|
def valid_signature?(signature, data, secret)
|
32
32
|
digest = OpenSSL::Digest.new('SHA1')
|
33
33
|
hmac = OpenSSL::HMAC.digest(digest, secret, data)
|
34
|
-
signature == Base64.encode64(hmac).chop
|
34
|
+
URI.decode(signature) == Base64.encode64(hmac).chop
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BeyondCanvas
|
4
|
+
module ResourceManagement # :nodoc:
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
# Share some methods defined in the controller to make them available for the view
|
9
|
+
if respond_to?(:helper_method)
|
10
|
+
helpers = %w[resource resource_name resource_class]
|
11
|
+
helper_method(*helpers)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def resource_name
|
18
|
+
BeyondCanvas.auth_model
|
19
|
+
end
|
20
|
+
|
21
|
+
def resource
|
22
|
+
instance_variable_get(:"@#{resource_name}")
|
23
|
+
end
|
24
|
+
|
25
|
+
def resource=(new_resource)
|
26
|
+
instance_variable_set(:"@#{resource_name}", new_resource)
|
27
|
+
end
|
28
|
+
|
29
|
+
def resource_class
|
30
|
+
resource_name.classify.constantize
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -2,18 +2,39 @@
|
|
2
2
|
|
3
3
|
module BeyondCanvas
|
4
4
|
class FormBuilder < ActionView::Helpers::FormBuilder # :nodoc:
|
5
|
+
############################################################################
|
6
|
+
# Wrappers
|
7
|
+
############################################################################
|
8
|
+
|
5
9
|
def field_wrapper(attribute, args, &block)
|
6
|
-
label = args[:label].presence || attribute.to_s.humanize
|
10
|
+
label = args[:label] == false ? nil : args[:label].presence || attribute.to_s.humanize
|
7
11
|
|
8
12
|
errors = object.errors[attribute].join(', ') if object.respond_to?(:errors) && object.errors.include?(attribute)
|
9
13
|
|
10
14
|
@template.content_tag(:div, class: 'form__row') do
|
11
15
|
@template.content_tag(:label, label, class: 'input__label') +
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
@template.content_tag(:div, class: 'relative') do
|
17
|
+
block.call +
|
18
|
+
(@template.content_tag(:label, errors, class: 'input__error') if errors.present?)
|
19
|
+
end +
|
20
|
+
(@template.content_tag(:div, args[:hint].html_safe, class: 'input__hint') if args[:hint].present?)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def inline_wrapper(attribute, args, &block)
|
25
|
+
label = args[:label] == false ? nil : args[:label].presence || attribute.to_s.humanize
|
26
|
+
|
27
|
+
errors = object.errors[attribute].join(', ') if object.respond_to?(:errors) && object.errors.include?(attribute)
|
28
|
+
|
29
|
+
@template.content_tag(:div, class: 'form__row') do
|
30
|
+
@template.content_tag(:div, class: 'relative', style: 'display: flex; align-items: center;') do
|
31
|
+
block.call +
|
32
|
+
@template.content_tag(:div) do
|
33
|
+
@template.content_tag(:label, label, class: 'input__label') +
|
34
|
+
(@template.content_tag(:div, args[:hint].html_safe, class: 'input__hint') if args[:hint].present?)
|
35
|
+
end +
|
36
|
+
(@template.content_tag(:label, errors, class: 'input__error') if errors.present?)
|
37
|
+
end
|
17
38
|
end
|
18
39
|
end
|
19
40
|
|
@@ -25,9 +46,39 @@ module BeyondCanvas
|
|
25
46
|
end
|
26
47
|
end
|
27
48
|
|
49
|
+
def check_box(attribute, args = {})
|
50
|
+
inline_wrapper(attribute, args) do
|
51
|
+
filed_identifyer = filed_identifyer(attribute)
|
52
|
+
|
53
|
+
args.merge!(id: filed_identifyer)
|
54
|
+
.merge!(hidden: true)
|
55
|
+
|
56
|
+
@template.content_tag(:div, class: 'input__checkbox') do
|
57
|
+
super(attribute, args) +
|
58
|
+
@template.content_tag(:label, nil, class: 'input__checkbox__control', for: filed_identifyer)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def radio_button(attribute, value, args = {})
|
64
|
+
args.merge!(label: value) unless args[:label]
|
65
|
+
|
66
|
+
inline_wrapper(attribute, args) do
|
67
|
+
filed_identifyer = filed_identifyer(attribute)
|
68
|
+
|
69
|
+
args.merge!(id: filed_identifyer)
|
70
|
+
.merge!(hidden: true)
|
71
|
+
|
72
|
+
@template.content_tag(:div, class: 'input__radio') do
|
73
|
+
super(attribute, value, args) +
|
74
|
+
@template.content_tag(:label, nil, class: 'input__radio__control', for: filed_identifyer)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
28
79
|
def file_field(attribute, args = {})
|
29
80
|
field_wrapper(attribute, args) do
|
30
|
-
filed_identifyer =
|
81
|
+
filed_identifyer = filed_identifyer(attribute)
|
31
82
|
|
32
83
|
args.merge!(id: filed_identifyer)
|
33
84
|
.merge!(hidden: true)
|
@@ -39,7 +90,7 @@ module BeyondCanvas
|
|
39
90
|
super(attribute, args) +
|
40
91
|
@template.content_tag(:label,
|
41
92
|
for: filed_identifyer,
|
42
|
-
class: '
|
93
|
+
class: 'input__file__control button__transparent--primary') do
|
43
94
|
args[:data][:button_text] || 'Choose file'
|
44
95
|
end +
|
45
96
|
@template.content_tag(:span,
|
@@ -48,5 +99,11 @@ module BeyondCanvas
|
|
48
99
|
end
|
49
100
|
end
|
50
101
|
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def filed_identifyer(attribute)
|
106
|
+
"#{attribute}_#{DateTime.now.strftime('%Q') + rand(10_000).to_s}"
|
107
|
+
end
|
51
108
|
end
|
52
109
|
end
|
@@ -1,7 +1,21 @@
|
|
1
|
-
|
1
|
+
import { disableActionElements, enableActionElements, hideSpinner, showSpinner } from './functions';
|
2
2
|
|
3
|
-
(function($) {
|
3
|
+
(function ($) {
|
4
4
|
const onDOMReady = function () {
|
5
|
+
const inputs = $('input, textarea, select').not(':input[type=button], :input[type=submit], :input[type=reset]');
|
6
|
+
|
7
|
+
inputs.each(function () {
|
8
|
+
var input = $(this);
|
9
|
+
|
10
|
+
input.bind('invalid', function (e) {
|
11
|
+
if ($(input).is(':hidden')) {
|
12
|
+
e.preventDefault();
|
13
|
+
}
|
14
|
+
hideSpinner();
|
15
|
+
enableActionElements();
|
16
|
+
});
|
17
|
+
});
|
18
|
+
|
5
19
|
$('button[class^="button"]').each(function () {
|
6
20
|
var button = $(this);
|
7
21
|
|
@@ -15,58 +29,26 @@ const SPINNER_ANIMATION_TIMEOUT = 125;
|
|
15
29
|
<div class="bounce1"></div>
|
16
30
|
<div class="bounce2"></div>
|
17
31
|
<div class="bounce3"></div>
|
18
|
-
</div>`
|
19
|
-
);
|
32
|
+
</div>`);
|
20
33
|
|
21
34
|
// Bind ajax:success and ajax:error to the form the button belongs to
|
22
35
|
button
|
23
36
|
.closest('form')
|
24
37
|
.on('ajax:success', function () {
|
25
|
-
hideSpinner(
|
38
|
+
hideSpinner();
|
26
39
|
enableActionElements();
|
27
40
|
})
|
28
41
|
.on('ajax:error', function () {
|
29
|
-
hideSpinner(
|
42
|
+
hideSpinner();
|
30
43
|
enableActionElements();
|
31
44
|
});
|
32
45
|
});
|
33
46
|
};
|
34
47
|
|
35
|
-
$(document).on('click', '[class^="button"]', function() {
|
48
|
+
$(document).on('click', '[class^="button"]', function () {
|
36
49
|
disableActionElements();
|
37
50
|
showSpinner($(this));
|
38
51
|
});
|
39
52
|
|
40
|
-
$(document)
|
41
|
-
.ready(onDOMReady)
|
42
|
-
.on('ready page:load turbolinks:load', onDOMReady);
|
53
|
+
$(document).on('ready page:load turbolinks:load', onDOMReady);
|
43
54
|
})(jQuery);
|
44
|
-
|
45
|
-
function showSpinner(button) {
|
46
|
-
// Adjust the width of the button
|
47
|
-
button.width(button.width() + $('.spinner').outerWidth(true));
|
48
|
-
// Show the spinner
|
49
|
-
setTimeout(function() {
|
50
|
-
button.find('.spinner').css('display', 'flex');
|
51
|
-
}, SPINNER_ANIMATION_TIMEOUT);
|
52
|
-
}
|
53
|
-
|
54
|
-
function hideSpinner(button) {
|
55
|
-
setTimeout(function () {
|
56
|
-
// Hide the spinner
|
57
|
-
button.find('.spinner').hide();
|
58
|
-
// Adjust the width of the button
|
59
|
-
button.width(button.data('oldWidth'));
|
60
|
-
}, SPINNER_ANIMATION_TIMEOUT);
|
61
|
-
}
|
62
|
-
|
63
|
-
function disableActionElements() {
|
64
|
-
$('a, input[type="submit"], input[type="button"], input[type="reset"], button').each(function() {
|
65
|
-
$(this).addClass('actions--disabled');
|
66
|
-
});
|
67
|
-
}
|
68
|
-
function enableActionElements() {
|
69
|
-
$('a, input[type="submit"], input[type="button"], input[type="reset"], button').each(function() {
|
70
|
-
$(this).removeClass("actions--disabled");
|
71
|
-
});
|
72
|
-
}
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
import { closeAlert } from './functions';
|
2
|
+
|
3
|
+
(function ($) {
|
2
4
|
const onDOMReady = function () {
|
3
5
|
$('.flash').each(function () {
|
4
6
|
$(this).css('right', -$(this).width() + 'px');
|
@@ -9,20 +11,9 @@
|
|
9
11
|
}, 100);
|
10
12
|
};
|
11
13
|
|
12
|
-
$(document).on('click', '.flash', function() {
|
14
|
+
$(document).on('click', '.flash', function () {
|
13
15
|
closeAlert();
|
14
16
|
});
|
15
17
|
|
16
|
-
$(document)
|
17
|
-
.ready(onDOMReady)
|
18
|
-
.on('ready page:load turbolinks:load', onDOMReady);
|
18
|
+
$(document).on('ready page:load turbolinks:load', onDOMReady);
|
19
19
|
})(jQuery);
|
20
|
-
|
21
|
-
function closeAlert() {
|
22
|
-
$('.flash')
|
23
|
-
.removeClass('flash--shown')
|
24
|
-
.delay(700)
|
25
|
-
.queue(function() {
|
26
|
-
$(this).remove();
|
27
|
-
});
|
28
|
-
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
const SPINNER_ANIMATION_TIMEOUT = 125;
|
2
|
+
|
3
|
+
export function showSpinner(button) {
|
4
|
+
// Adjust the width of the button
|
5
|
+
button.width(button.width() + $('.spinner').outerWidth(true));
|
6
|
+
// Show the spinner
|
7
|
+
setTimeout(function () {
|
8
|
+
button.find('.spinner').css('display', 'flex');
|
9
|
+
}, SPINNER_ANIMATION_TIMEOUT);
|
10
|
+
}
|
11
|
+
|
12
|
+
export function hideSpinner() {
|
13
|
+
$('button[class^="button"]').each(function (_, button) {
|
14
|
+
setTimeout(function () {
|
15
|
+
// Hide the spinner
|
16
|
+
$(button).find('.spinner').hide();
|
17
|
+
// Adjust the width of the button
|
18
|
+
$(button).width($(button).data('oldWidth'));
|
19
|
+
}, SPINNER_ANIMATION_TIMEOUT);
|
20
|
+
});
|
21
|
+
}
|
22
|
+
|
23
|
+
export function disableActionElements() {
|
24
|
+
$('a, input[type="submit"], input[type="button"], input[type="reset"], button').each(function (_, button) {
|
25
|
+
$(button).addClass('actions--disabled');
|
26
|
+
});
|
27
|
+
}
|
28
|
+
export function enableActionElements() {
|
29
|
+
$('a, input[type="submit"], input[type="button"], input[type="reset"], button').each(function (_, button) {
|
30
|
+
$(button).removeClass('actions--disabled');
|
31
|
+
});
|
32
|
+
}
|
33
|
+
|
34
|
+
export function closeAlert() {
|
35
|
+
$('.flash')
|
36
|
+
.removeClass('flash--shown')
|
37
|
+
.delay(700)
|
38
|
+
.queue(function () {
|
39
|
+
$(this).remove();
|
40
|
+
});
|
41
|
+
}
|