workarea-yotpo 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +20 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  4. data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  6. data/.github/workflows/ci.yml +54 -0
  7. data/.gitignore +23 -0
  8. data/.rubocop.yml +3 -0
  9. data/.travis.yml +27 -0
  10. data/CHANGELOG.md +20 -0
  11. data/CODE_OF_CONDUCT.md +3 -0
  12. data/CONTRIBUTING.md +3 -0
  13. data/Gemfile +6 -0
  14. data/LICENSE.md +3 -0
  15. data/README.md +86 -0
  16. data/Rakefile +60 -0
  17. data/app/assets/images/yotpo/.keep +0 -0
  18. data/app/assets/javascripts/yotpo/.keep +0 -0
  19. data/app/assets/stylesheets/yotpo/.keep +0 -0
  20. data/app/controllers/.keep +0 -0
  21. data/app/helpers/.keep +0 -0
  22. data/app/mailers/.keep +0 -0
  23. data/app/models/.keep +0 -0
  24. data/app/services/yotpo/order.rb +81 -0
  25. data/app/views/workarea/storefront/_yotpo_tracking.html.haml +3 -0
  26. data/app/views/workarea/storefront/checkouts/_yotpo_order_tracking.html.haml +7 -0
  27. data/app/views/workarea/storefront/products/_yotpo_product_summary.html.haml +2 -0
  28. data/app/views/workarea/storefront/products/_yotpo_reviews.html.haml +2 -0
  29. data/app/views/workarea/storefront/products/_yotpo_summary.html.haml +2 -0
  30. data/app/workers/workarea/yotpo/save_order.rb +20 -0
  31. data/bin/rails +25 -0
  32. data/config/initializers/appends.rb +24 -0
  33. data/config/initializers/workarea.rb +11 -0
  34. data/config/routes.rb +2 -0
  35. data/lib/workarea/yotpo.rb +41 -0
  36. data/lib/workarea/yotpo/authentication.rb +45 -0
  37. data/lib/workarea/yotpo/bogus_gateway.rb +33 -0
  38. data/lib/workarea/yotpo/engine.rb +10 -0
  39. data/lib/workarea/yotpo/gateway.rb +64 -0
  40. data/lib/workarea/yotpo/response.rb +17 -0
  41. data/lib/workarea/yotpo/version.rb +5 -0
  42. data/script/static_analysis +29 -0
  43. data/script/travis +6 -0
  44. data/test/dummy/.ruby-version +1 -0
  45. data/test/dummy/Rakefile +6 -0
  46. data/test/dummy/app/assets/config/manifest.js +3 -0
  47. data/test/dummy/app/assets/images/.keep +0 -0
  48. data/test/dummy/app/assets/javascripts/application.js +14 -0
  49. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  50. data/test/dummy/app/controllers/application_controller.rb +2 -0
  51. data/test/dummy/app/controllers/concerns/.keep +0 -0
  52. data/test/dummy/app/helpers/application_helper.rb +2 -0
  53. data/test/dummy/app/jobs/application_job.rb +2 -0
  54. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  55. data/test/dummy/app/models/concerns/.keep +0 -0
  56. data/test/dummy/app/views/layouts/application.html.erb +15 -0
  57. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  58. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  59. data/test/dummy/bin/bundle +3 -0
  60. data/test/dummy/bin/rails +4 -0
  61. data/test/dummy/bin/rake +4 -0
  62. data/test/dummy/bin/setup +28 -0
  63. data/test/dummy/bin/update +28 -0
  64. data/test/dummy/bin/yarn +11 -0
  65. data/test/dummy/config.ru +5 -0
  66. data/test/dummy/config/application.rb +34 -0
  67. data/test/dummy/config/boot.rb +5 -0
  68. data/test/dummy/config/environment.rb +5 -0
  69. data/test/dummy/config/environments/development.rb +52 -0
  70. data/test/dummy/config/environments/production.rb +83 -0
  71. data/test/dummy/config/environments/test.rb +45 -0
  72. data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
  73. data/test/dummy/config/initializers/assets.rb +14 -0
  74. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  75. data/test/dummy/config/initializers/content_security_policy.rb +25 -0
  76. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  77. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  78. data/test/dummy/config/initializers/inflections.rb +16 -0
  79. data/test/dummy/config/initializers/mime_types.rb +4 -0
  80. data/test/dummy/config/initializers/workarea.rb +5 -0
  81. data/test/dummy/config/initializers/wrap_parameters.rb +9 -0
  82. data/test/dummy/config/locales/en.yml +33 -0
  83. data/test/dummy/config/puma.rb +34 -0
  84. data/test/dummy/config/routes.rb +5 -0
  85. data/test/dummy/config/spring.rb +6 -0
  86. data/test/dummy/db/seeds.rb +2 -0
  87. data/test/dummy/lib/assets/.keep +0 -0
  88. data/test/dummy/log/.keep +0 -0
  89. data/test/integration/workarea/yotpo/yotpo_integration_test.rb +44 -0
  90. data/test/services/yotpo/order_test.rb +61 -0
  91. data/test/teaspoon_env.rb +6 -0
  92. data/test/test_helper.rb +10 -0
  93. data/test/workers/workarea/yotpo/save_order_test.rb +13 -0
  94. data/workarea-yotpo.gemspec +20 -0
  95. metadata +163 -0
@@ -0,0 +1,3 @@
1
+ - if Workarea::Yotpo.app_key.present?
2
+ %script{ type: "text/javascript" }
3
+ (function e(){var e=document.createElement("script");e.type="text/javascript",e.async=true,e.src="//staticw2.yotpo.com/#{Workarea::Yotpo.app_key}/widget.js";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)})();
@@ -0,0 +1,7 @@
1
+ - if Workarea::Yotpo.app_key.present?
2
+ :javascript
3
+ (function e(){var e=document.createElement("script");e.type="text/javascript",e.async=true,e.src="//staticw2.yotpo.com/#{Workarea::Yotpo.app_key}/widget.js";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)})();
4
+ :javascript
5
+ yotpoTrackConversionData = {orderId: "#{@order.id}", orderAmount: "#{@order.total_price}", orderCurrency: "#{@order.total_price.currency.iso_code}"}
6
+ %noscript
7
+ %img{:height => "1", :src => "//api.yotpo.com/conversion_tracking.gif?app_key=#{Workarea::Yotpo.app_key}&order_id=#{@order.id}&order_amount=#{@order.total_price}&order_currency=#{@order.total_price.currency.iso_code}", :width => "1"}/
@@ -0,0 +1,2 @@
1
+ - if Workarea::Yotpo.app_key.present? && Workarea.config.yotpo.show_review_summary_on_pdp
2
+ .yotpo.bottomLine{"data-product-id" => "#{product.id}", "data-url" => "#{product_url(product)}"}
@@ -0,0 +1,2 @@
1
+ - if Workarea::Yotpo.app_key.present?
2
+ .yotpo.yotpo-main-widget{"data-currency" => "#{product.sell_min_price.currency}", "data-image-url" => "#{product_image_url(product.primary_image, :small)}", "data-name" => "#{product.name}", "data-price" => "#{product.pricing.sell_min_price}", "data-product-id" => "#{product.id}", "data-url" => "#{product_url(product)}" }
@@ -0,0 +1,2 @@
1
+ - if Workarea::Yotpo.app_key.present? && Workarea.config.yotpo.show_review_summary_on_product_summary
2
+ .yotpo.bottomLine{"data-product-id" => "#{product.id}", "data-url" => "#{product_url(product)}"}
@@ -0,0 +1,20 @@
1
+ module Workarea
2
+ module Yotpo
3
+ class SaveOrder
4
+ include Sidekiq::Worker
5
+ include Sidekiq::CallbacksWorker
6
+
7
+ sidekiq_options(
8
+ enqueue_on: { Workarea::Order => [:place] },
9
+ unique: :until_executing
10
+ )
11
+
12
+ def perform(id)
13
+ order = Workarea::Order.find(id)
14
+ yotpo_order = Workarea::Yotpo::Order.new(order.id)
15
+
16
+ Workarea::Yotpo.gateway.create_order(yotpo_order.to_h)
17
+ end
18
+ end
19
+ end
20
+ end
data/bin/rails ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails gems
3
+ # installed from the root of your application.
4
+
5
+ ENGINE_ROOT = File.expand_path('..', __dir__)
6
+ ENGINE_PATH = File.expand_path('../lib/workarea/yotpo/engine', __dir__)
7
+ APP_PATH = File.expand_path('../test/dummy/config/application', __dir__)
8
+
9
+ # Set up gems listed in the Gemfile.
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
11
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
12
+
13
+ require "rails"
14
+ # Pick the frameworks you want:
15
+ require "active_model/railtie"
16
+ require "active_job/railtie"
17
+ # require "active_record/railtie"
18
+ # require "active_storage/engine"
19
+ require "action_controller/railtie"
20
+ require "action_mailer/railtie"
21
+ require "action_view/railtie"
22
+ # require "action_cable/engine"
23
+ require "sprockets/railtie"
24
+ require "rails/test_unit/railtie"
25
+ require 'rails/engine/commands'
@@ -0,0 +1,24 @@
1
+ Workarea.append_partials(
2
+ 'storefront.document_head',
3
+ 'workarea/storefront/yotpo_tracking'
4
+ )
5
+
6
+ Workarea.append_partials(
7
+ 'storefront.product_show',
8
+ 'workarea/storefront/products/yotpo_reviews'
9
+ )
10
+
11
+ Workarea.append_partials(
12
+ 'storefront.product_details',
13
+ 'workarea/storefront/products/yotpo_product_summary'
14
+ )
15
+
16
+ Workarea.append_partials(
17
+ 'storefront.product_summary',
18
+ 'workarea/storefront/products/yotpo_summary'
19
+ )
20
+
21
+ Workarea.append_partials(
22
+ 'storefront.checkout_confirmation',
23
+ 'workarea/storefront/checkouts/yotpo_order_tracking'
24
+ )
@@ -0,0 +1,11 @@
1
+ Workarea.configure do |config|
2
+ config.yotpo = ActiveSupport::Configurable::Configuration.new
3
+ config.yotpo.app_key = nil # js sdk integration
4
+
5
+ # show review summary on PDP
6
+ config.yotpo.show_review_summary_on_pdp = true
7
+
8
+ # show review summaries on product summaries in search,
9
+ # browse, and recomendation
10
+ config.yotpo.show_review_summary_on_product_summary = true
11
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ Rails.application.routes.draw do
2
+ end
@@ -0,0 +1,41 @@
1
+ require 'workarea'
2
+ require 'workarea/storefront'
3
+ require 'workarea/admin'
4
+
5
+ require 'workarea/yotpo/engine'
6
+ require 'workarea/yotpo/version'
7
+
8
+ require 'workarea/yotpo/authentication'
9
+ require 'workarea/yotpo/gateway'
10
+ require 'workarea/yotpo/bogus_gateway'
11
+ require 'workarea/yotpo/response'
12
+
13
+ require 'faraday'
14
+
15
+ module Workarea
16
+ module Yotpo
17
+ def self.credentials
18
+ (Rails.application.secrets.yotpo || {}).deep_symbolize_keys
19
+ end
20
+
21
+ def self.config
22
+ Workarea.config.yotpo
23
+ end
24
+
25
+ def self.app_key
26
+ config.app_key
27
+ end
28
+
29
+ def self.secret_key
30
+ credentials[:secret_key]
31
+ end
32
+
33
+ def self.gateway
34
+ if credentials.present?
35
+ Workarea::Yotpo::Gateway.new(app_key: app_key, secret_key: secret_key)
36
+ else
37
+ Workarea::Yotpo::BogusGateway.new
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,45 @@
1
+ module Workarea
2
+ module Yotpo
3
+ module Authentication
4
+ class NoTokenError < StandardError; end
5
+
6
+ def token
7
+ response = get_token
8
+ raise NoTokenError unless response.present? && response.success?
9
+
10
+ body = JSON.parse(response.body)
11
+ body['access_token']
12
+ end
13
+
14
+ private
15
+
16
+ def get_token
17
+ conn = Faraday.new(url: auth_endpoint)
18
+ conn.post do |req|
19
+ req.url '/oauth/token', token_params
20
+ req.headers['Content-Type'] = 'application/json'
21
+ end
22
+ end
23
+
24
+ def token_params
25
+ {
26
+ client_id: client_id,
27
+ client_secret: client_secret,
28
+ grant_type: 'client_credentials'
29
+ }
30
+ end
31
+
32
+ def auth_endpoint
33
+ "https://api.yotpo.com"
34
+ end
35
+
36
+ def client_id
37
+ options[:app_key]
38
+ end
39
+
40
+ def client_secret
41
+ options[:secret_key]
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,33 @@
1
+ module Workarea
2
+ module Yotpo
3
+ class BogusGateway
4
+ attr_reader :options
5
+
6
+ def initialize(options = {})
7
+ @options = options
8
+ end
9
+
10
+ def create_order(order_details)
11
+ Response.new(response)
12
+ end
13
+
14
+ private
15
+ def response
16
+ response = Faraday.new do |builder|
17
+ builder.adapter :test do |stub|
18
+ stub.get('/rest/bogus.json') { |env| [ 200, {}, response_body ] }
19
+ end
20
+ end
21
+ response.get('/rest/bogus.json')
22
+ end
23
+
24
+ def response_body
25
+ {
26
+ code: 200,
27
+ message: "OK",
28
+ uuid: "4161933d-9213-45ee-beb4-cb3ac2844345"
29
+ }.to_json
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,10 @@
1
+ require 'workarea/yotpo'
2
+
3
+ module Workarea
4
+ module Yotpo
5
+ class Engine < ::Rails::Engine
6
+ include Workarea::Plugin
7
+ isolate_namespace Workarea::Yotpo
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,64 @@
1
+ module Workarea
2
+ module Yotpo
3
+ class Gateway
4
+ include Yotpo::Authentication
5
+ class YotpoGatewayError < StandardError; end
6
+
7
+ attr_reader :options
8
+
9
+ def initialize(options = {})
10
+ requires!(options, :app_key, :secret_key)
11
+ @options = options
12
+ end
13
+
14
+ def create_order(order_details)
15
+ auth_creds = {
16
+ utoken: token,
17
+ app_key: client_id
18
+ }
19
+
20
+ body = order_details.merge(auth_creds).to_json
21
+
22
+ response = connection.post do |req|
23
+ req.url "apps/#{client_id}/purchases/"
24
+ req.body = body
25
+ end
26
+
27
+ Response.new(response)
28
+ end
29
+
30
+ private
31
+
32
+ def rest_endpoint
33
+ 'https://api.yotpo.com'
34
+ end
35
+
36
+ def connection
37
+ headers = {
38
+ 'Content-Type' => 'application/json',
39
+ 'Authorization' => "Bearer #{token}"
40
+ }
41
+
42
+ request_timeouts = {
43
+ timeout: Workarea.config.yotpo.api_timeout,
44
+ open_timeout: Workarea.config.yotpo.open_timeout
45
+ }
46
+
47
+ Faraday.new(url: rest_endpoint, headers: headers, request: request_timeouts)
48
+ end
49
+
50
+ def requires!(hash, *params)
51
+ params.each do |param|
52
+ if param.is_a?(Array)
53
+ raise ArgumentError.new("Missing required parameter: #{param.first}") unless hash.has_key?(param.first)
54
+
55
+ valid_options = param[1..-1]
56
+ raise ArgumentError.new("Parameter: #{param.first} must be one of #{valid_options.to_sentence(words_connector: 'or')}") unless valid_options.include?(hash[param.first])
57
+ else
58
+ raise ArgumentError.new("Missing required parameter: #{param}") unless hash.has_key?(param)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,17 @@
1
+ module Workarea
2
+ module Yotpo
3
+ class Response
4
+ def initialize(response)
5
+ @response = response
6
+ end
7
+
8
+ def success?
9
+ @response.success?
10
+ end
11
+
12
+ def body
13
+ @body ||= JSON.parse(@response.body)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ module Workarea
2
+ module Yotpo
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env bash
2
+
3
+ echo "*************************************************************************"
4
+ echo "Running Bundler Audit..."
5
+ bundle exec bundle-audit check --update
6
+ rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi
7
+
8
+ echo ""
9
+ echo ""
10
+ echo "*************************************************************************"
11
+ echo "Running Rubocop..."
12
+ bundle exec rubocop
13
+ rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi
14
+
15
+ yarn init -yp --silent
16
+
17
+ echo ""
18
+ echo ""
19
+ echo "*************************************************************************"
20
+ echo "Running ESLint..."
21
+ yarn add --silent --dev eslint@4.19.1 --loglevel error
22
+ yarn run eslint admin/app/**/*.js admin/**/test/**/*.js core/app/**/*.js core/**/test/**/*.js storefront/app/**/*.js storefront/**/test/**/*.js
23
+ rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi
24
+
25
+ echo ""
26
+ echo "*************************************************************************"
27
+ echo "Running Stylelint..."
28
+ yarn add --silent --dev stylelint@9.2.1 stylelint-scss@3.1.0 stylelint-config-recommended-scss@3.2.0
29
+ yarn run stylelint admin/app/**/*.scss core/app/**/*.scss storefront/app/**/*.scss
data/script/travis ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+
3
+ bundle exec rake workarea:services:up
4
+ sleep 10 # to let Elasticsearch prepare itself
5
+
6
+ eval $TEST_COMMAND
@@ -0,0 +1 @@
1
+ 2.4.3
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative 'config/application'
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,3 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../javascripts .js
3
+ //= link_directory ../stylesheets .css
File without changes
@@ -0,0 +1,14 @@
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. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require rails-ujs
14
+ //= require_tree .
@@ -0,0 +1,15 @@
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 other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,2 @@
1
+ class ApplicationController < ActionController::Base
2
+ end
File without changes