beyond_canvas 0.14.0.pre → 0.16.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +0 -6
  3. data/app/assets/images/icons/checkbox_checked.svg +1 -0
  4. data/app/assets/images/icons/checkbox_unchecked.svg +1 -0
  5. data/app/assets/images/icons/radiobutton_checked.svg +1 -0
  6. data/app/assets/images/icons/radiobutton_unchecked.svg +1 -0
  7. data/app/assets/javascripts/beyond_canvas/base.js +248 -87
  8. data/app/assets/stylesheets/beyond_canvas/base.scss +3 -0
  9. data/app/assets/stylesheets/beyond_canvas/components/_containers.scss +37 -0
  10. data/app/assets/stylesheets/beyond_canvas/components/_inputs.scss +47 -1
  11. data/app/assets/stylesheets/beyond_canvas/settings/_breakpoints.scss +6 -0
  12. data/app/assets/stylesheets/beyond_canvas/settings/_variables.scss +24 -0
  13. data/app/assets/stylesheets/beyond_canvas/utilities/_functions.scss +15 -0
  14. data/app/controllers/beyond_canvas/authentications_controller.rb +62 -0
  15. data/app/controllers/concerns/beyond_canvas/authentication.rb +24 -0
  16. data/app/controllers/concerns/beyond_canvas/request_validation.rb +1 -1
  17. data/app/controllers/concerns/beyond_canvas/resource_management.rb +33 -0
  18. data/app/form_builders/beyond_canvas/form_builder.rb +65 -8
  19. data/app/javascript/beyond_canvas/base.js +3 -6
  20. data/app/javascript/beyond_canvas/initializers/buttons.js +21 -39
  21. data/app/javascript/beyond_canvas/initializers/flash.js +5 -14
  22. data/app/javascript/beyond_canvas/initializers/functions.js +41 -0
  23. data/app/javascript/beyond_canvas/initializers/inputs.js +3 -8
  24. data/app/views/beyond_canvas/authentications/new.html.erb +18 -0
  25. data/config/locales/en.yml +4 -0
  26. data/config/routes.rb +6 -0
  27. data/lib/beyond_canvas.rb +22 -2
  28. data/lib/beyond_canvas/configuration.rb +4 -1
  29. data/lib/beyond_canvas/engine.rb +4 -0
  30. data/lib/beyond_canvas/models/authentication.rb +66 -0
  31. data/lib/beyond_canvas/models/shop.rb +28 -0
  32. data/lib/beyond_canvas/models/utils.rb +55 -0
  33. data/lib/beyond_canvas/parameter_sanitizer.rb +43 -0
  34. data/lib/beyond_canvas/rails/routes.rb +21 -0
  35. data/lib/beyond_canvas/version.rb +1 -1
  36. data/lib/generators/beyond_canvas/auth_model/auth_model_generator.rb +50 -0
  37. data/lib/generators/beyond_canvas/auth_model/templates/migration.erb +20 -0
  38. data/lib/generators/beyond_canvas/auth_model/templates/model.erb +5 -0
  39. data/lib/generators/beyond_canvas/controller/controller_generator.rb +20 -0
  40. data/lib/generators/beyond_canvas/controller/templates/controller.erb +37 -0
  41. data/lib/generators/beyond_canvas/install/install_generator.rb +15 -5
  42. data/lib/generators/beyond_canvas/install/templates/beyond_canvas.rb.erb +11 -0
  43. data/lib/generators/beyond_canvas/views/views_generator.rb +19 -0
  44. metadata +58 -6
@@ -0,0 +1,6 @@
1
+ $mobile-s: 321px !global;
2
+ $mobile-m: 376px !global;
3
+ $mobile-l: 426px !global;
4
+ $tablet: 769px !global;
5
+ $laptop: 1025px !global;
6
+ $laptop-l: 1441px !global;
@@ -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
- @template.content_tag(:div, class: 'relative') do
13
- block.call +
14
- (@template.content_tag(:label, errors, class: 'input__error') if errors.present?)
15
- end +
16
- (@template.content_tag(:div, args[:hint].html_safe, class: 'input__hint') if args[:hint].present?)
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 = "#{attribute}_#{(Time.now.to_f * 1000).to_i}"
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: 'input__file__label button__transparent--primary') do
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,6 +1,3 @@
1
- import 'jquery'
2
- import 'jquery-ujs'
3
-
4
- import './initializers/buttons'
5
- import './initializers/flash'
6
- import './initializers/inputs'
1
+ import './initializers/buttons';
2
+ import './initializers/flash';
3
+ import './initializers/inputs';
@@ -1,7 +1,21 @@
1
- const SPINNER_ANIMATION_TIMEOUT = 125;
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(button);
38
+ hideSpinner();
26
39
  enableActionElements();
27
40
  })
28
41
  .on('ajax:error', function () {
29
- hideSpinner(button);
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
- (function($) {
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
+ }