spiffy_stores_app 8.2.6

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 (68) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rubocop.yml +7 -0
  4. data/.travis.yml +9 -0
  5. data/CHANGELOG.md +3 -0
  6. data/Gemfile +6 -0
  7. data/README.md +346 -0
  8. data/Rakefile +6 -0
  9. data/app/assets/javascripts/spiffy_stores_app/redirect.js +19 -0
  10. data/app/controllers/spiffy_stores_app/authenticated_controller.rb +11 -0
  11. data/app/controllers/spiffy_stores_app/sessions_controller.rb +113 -0
  12. data/app/controllers/spiffy_stores_app/webhooks_controller.rb +36 -0
  13. data/app/views/spiffy_stores_app/sessions/new.html.erb +123 -0
  14. data/app/views/spiffy_stores_app/shared/redirect.html.erb +22 -0
  15. data/config/locales/de.yml +3 -0
  16. data/config/locales/en.yml +4 -0
  17. data/config/locales/es.yml +3 -0
  18. data/config/locales/fr.yml +4 -0
  19. data/config/locales/ja.yml +3 -0
  20. data/config/routes.rb +12 -0
  21. data/docs/Quickstart.md +76 -0
  22. data/images/app-proxy-screenshot.png +0 -0
  23. data/lib/generators/spiffy_stores_app/add_after_authenticate_job/add_after_authenticate_job_generator.rb +43 -0
  24. data/lib/generators/spiffy_stores_app/add_after_authenticate_job/templates/after_authenticate_job.rb +10 -0
  25. data/lib/generators/spiffy_stores_app/add_webhook/add_webhook_generator.rb +68 -0
  26. data/lib/generators/spiffy_stores_app/add_webhook/templates/webhook_job.rb +8 -0
  27. data/lib/generators/spiffy_stores_app/app_proxy_controller/app_proxy_controller_generator.rb +25 -0
  28. data/lib/generators/spiffy_stores_app/app_proxy_controller/templates/app_proxy_controller.rb +8 -0
  29. data/lib/generators/spiffy_stores_app/app_proxy_controller/templates/app_proxy_route.rb +10 -0
  30. data/lib/generators/spiffy_stores_app/app_proxy_controller/templates/index.html.erb +19 -0
  31. data/lib/generators/spiffy_stores_app/controllers/controllers_generator.rb +29 -0
  32. data/lib/generators/spiffy_stores_app/home_controller/home_controller_generator.rb +31 -0
  33. data/lib/generators/spiffy_stores_app/home_controller/templates/home_controller.rb +6 -0
  34. data/lib/generators/spiffy_stores_app/home_controller/templates/index.html.erb +21 -0
  35. data/lib/generators/spiffy_stores_app/home_controller/templates/spiffy_stores_app_ready_script.html.erb +7 -0
  36. data/lib/generators/spiffy_stores_app/install/install_generator.rb +58 -0
  37. data/lib/generators/spiffy_stores_app/install/templates/_flash_messages.html.erb +19 -0
  38. data/lib/generators/spiffy_stores_app/install/templates/embedded_app.html.erb +40 -0
  39. data/lib/generators/spiffy_stores_app/install/templates/omniauth.rb +2 -0
  40. data/lib/generators/spiffy_stores_app/install/templates/spiffy_provider.rb +11 -0
  41. data/lib/generators/spiffy_stores_app/install/templates/spiffy_stores_app.rb +9 -0
  42. data/lib/generators/spiffy_stores_app/routes/routes_generator.rb +31 -0
  43. data/lib/generators/spiffy_stores_app/routes/templates/routes.rb +11 -0
  44. data/lib/generators/spiffy_stores_app/shop_model/shop_model_generator.rb +38 -0
  45. data/lib/generators/spiffy_stores_app/shop_model/templates/db/migrate/create_shops.erb +15 -0
  46. data/lib/generators/spiffy_stores_app/shop_model/templates/shop.rb +3 -0
  47. data/lib/generators/spiffy_stores_app/shop_model/templates/shops.yml +3 -0
  48. data/lib/generators/spiffy_stores_app/spiffy_stores_app_generator.rb +16 -0
  49. data/lib/generators/spiffy_stores_app/views/views_generator.rb +29 -0
  50. data/lib/spiffy_stores_app.rb +34 -0
  51. data/lib/spiffy_stores_app/configuration.rb +72 -0
  52. data/lib/spiffy_stores_app/controller_concerns/app_proxy_verification.rb +38 -0
  53. data/lib/spiffy_stores_app/controller_concerns/embedded_app.rb +19 -0
  54. data/lib/spiffy_stores_app/controller_concerns/localization.rb +22 -0
  55. data/lib/spiffy_stores_app/controller_concerns/login_protection.rb +103 -0
  56. data/lib/spiffy_stores_app/controller_concerns/webhook_verification.rb +34 -0
  57. data/lib/spiffy_stores_app/engine.rb +10 -0
  58. data/lib/spiffy_stores_app/jobs/scripttags_manager_job.rb +15 -0
  59. data/lib/spiffy_stores_app/jobs/webhooks_manager_job.rb +15 -0
  60. data/lib/spiffy_stores_app/managers/scripttags_manager.rb +77 -0
  61. data/lib/spiffy_stores_app/managers/webhooks_manager.rb +61 -0
  62. data/lib/spiffy_stores_app/session/in_memory_session_store.rb +27 -0
  63. data/lib/spiffy_stores_app/session/session_repository.rb +34 -0
  64. data/lib/spiffy_stores_app/session/session_storage.rb +32 -0
  65. data/lib/spiffy_stores_app/utils.rb +16 -0
  66. data/lib/spiffy_stores_app/version.rb +3 -0
  67. data/spiffy_stores_app.gemspec +26 -0
  68. metadata +220 -0
@@ -0,0 +1,36 @@
1
+ module SpiffyStoresApp
2
+ class WebhooksController < ActionController::Base
3
+ include SpiffyStoresApp::WebhookVerification
4
+
5
+ class SpiffyStoresApp::MissingWebhookJobError < StandardError; end
6
+
7
+ def receive
8
+ params.permit!
9
+ job_args = {shop_domain: shop_domain, webhook: webhook_params.to_h}
10
+ webhook_job_klass.perform_later(job_args)
11
+ head :no_content
12
+ end
13
+
14
+ private
15
+
16
+ def webhook_params
17
+ params.except(:controller, :action, :type)
18
+ end
19
+
20
+ def webhook_job_klass
21
+ webhook_job_klass_name.safe_constantize or raise SpiffyStoresApp::MissingWebhookJobError
22
+ end
23
+
24
+ def webhook_job_klass_name(type = webhook_type)
25
+ [webhook_namespace, "#{type}_job"].compact.join('/').classify
26
+ end
27
+
28
+ def webhook_type
29
+ params[:type]
30
+ end
31
+
32
+ def webhook_namespace
33
+ SpiffyStoresApp.configuration.webhook_jobs_namespace
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,123 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <title>Spiffy Stores App — Installation</title>
5
+
6
+ <meta http-equiv="x-ua-compatible" content="ie=edge">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+
9
+ <style>
10
+ * {
11
+ -moz-box-sizing: border-box;
12
+ -webkit-box-sizing: border-box;
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ body {
17
+ padding: 2.5em 0;
18
+ color: #212b37;
19
+ font-family: -apple-system,BlinkMacSystemFont,San Francisco,Roboto,Segoe UI,Helvetica Neue,sans-serif;
20
+ }
21
+
22
+ .container {
23
+ width: 100%;
24
+ text-align: center;
25
+ margin-left: auto;
26
+ margin-right: auto;
27
+ }
28
+
29
+ @media screen and (min-width: 510px) {
30
+ .container {
31
+ width: 510px;
32
+ }
33
+ }
34
+
35
+ .title {
36
+ font-size: 1.5em;
37
+ margin: 2em auto;
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: center;
41
+ word-break: break-all;
42
+ }
43
+
44
+ .subtitle {
45
+ font-size: 0.8em;
46
+ font-weight: 500;
47
+ color: #64737f;
48
+ line-height: 2em;
49
+ }
50
+
51
+ .error {
52
+ line-height: 1em;
53
+ padding: 0.5em;
54
+ color: red;
55
+ }
56
+
57
+ input.marketing-input {
58
+ width: 100%;
59
+ height: 52px;
60
+ padding: 0 15px;
61
+ box-shadow: 0 0 0 1px #ddd;
62
+ border: 0;
63
+ border-radius: 5px;
64
+ background-color: #fff;
65
+ font-size: 1em;
66
+ margin-bottom: 15px;
67
+ }
68
+
69
+ input.marketing-input:focus {
70
+ color: #000;
71
+ outline: 0;
72
+ box-shadow: 0 0 0 2px #5e6ebf;
73
+ }
74
+
75
+ button.marketing-button {
76
+ display: inline-block;
77
+ width: 100%;
78
+ padding: 1.0625em 1.875em;
79
+ background-color: #5e6ebf;
80
+ color: #fff;
81
+ font-weight: 700;
82
+ font-size: 1em;
83
+ text-align: center;
84
+ outline: none;
85
+ border: 0 solid transparent;
86
+ border-radius: 5px;
87
+ cursor: pointer;
88
+ }
89
+
90
+ button.marketing-button:hover {
91
+ background: linear-gradient(to bottom, #5c6ac4, #4959bd);
92
+ border-color: #3f4eae;
93
+ }
94
+
95
+ button.marketing-button:focus {
96
+ box-shadow: 0 0 0.1875em 0.1875em rgba(94,110,191,0.5);
97
+ background-color: #223274;
98
+ color: #fff;
99
+ }
100
+ </style>
101
+ </head>
102
+ <body>
103
+
104
+ <main class="container" role="main">
105
+ <% application_name = SpiffyStoresApp.configuration.application_name %>
106
+ <h3 class="title">
107
+ <%= application_name.presence || 'Spiffy Stores App - Installation' %>
108
+ </h3>
109
+ <p class="subtitle">
110
+ <label for="store">Please enter the name of your "spiffystores.com" store</label>
111
+ </p>
112
+
113
+ <%= form_tag login_path do %>
114
+ <% if flash[:error] %>
115
+ <div class="error"><%= flash[:error] %></div>
116
+ <% end %>
117
+ <input id="store" name="store" type="text" autofocus="autofocus" placeholder="mystore.spiffystores.com" class="marketing-input">
118
+ <button type="submit" class="marketing-button">Install</button>
119
+ <% end %>
120
+ </main>
121
+
122
+ </body>
123
+ </html>
@@ -0,0 +1,22 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <base target="_top">
6
+ <title>Redirecting…</title>
7
+ <%= javascript_include_tag('spiffy_stores_app/redirect', crossorigin: 'anonymous', integrity: true) %>
8
+ </head>
9
+ <body>
10
+ <%=
11
+ content_tag(:div, nil,
12
+ id: 'redirection-target',
13
+ data: {
14
+ target: {
15
+ myspiffyUrl: "https://#{current_spiffy_stores_domain}",
16
+ url: url,
17
+ },
18
+ },
19
+ )
20
+ %>
21
+ </body>
22
+ </html>
@@ -0,0 +1,3 @@
1
+ de:
2
+ logged_out: 'Erfolgreich ausgelogt'
3
+ could_not_log_in: 'Spiffy Stores Store Login fehlgeschlagen'
@@ -0,0 +1,4 @@
1
+ en:
2
+ logged_out: 'Successfully logged out'
3
+ could_not_log_in: 'Could not log in to Spiffy Stores store'
4
+ invalid_shop_url: 'Invalid store domain'
@@ -0,0 +1,3 @@
1
+ es:
2
+ logged_out: 'Cerrar sesión'
3
+ could_not_log_in: 'No se pudo iniciar sesión en tu tienda de Spiffy Stores'
@@ -0,0 +1,4 @@
1
+ fr:
2
+ logged_out: 'Vous êtes déconnecté(e)'
3
+ could_not_log_in: 'Impossible de se connecter à la boutique Spiffy Stores'
4
+ invalid_shop_url: 'Url invalide'
@@ -0,0 +1,3 @@
1
+ ja:
2
+ logged_out: 'ログインに成功しました'
3
+ could_not_log_in: 'Spiffy Stores ストアにログインできませんでした'
@@ -0,0 +1,12 @@
1
+ SpiffyStoresApp::Engine.routes.draw do
2
+ controller :sessions do
3
+ get 'login' => :new, :as => :login
4
+ post 'login' => :create, :as => :authenticate
5
+ get 'auth/spiffy/callback' => :callback
6
+ get 'logout' => :destroy, :as => :logout
7
+ end
8
+
9
+ namespace :webhooks do
10
+ post ':type' => :receive
11
+ end
12
+ end
@@ -0,0 +1,76 @@
1
+ Quickstart
2
+ ==========
3
+
4
+ Build and deploy a new Spiffy Stores App to Heroku in minutes
5
+
6
+ 1. New Rails App (with postgres)
7
+ --------------------------------
8
+
9
+ ```sh
10
+ $ rails new test-app --database=postgresql
11
+ $ cd test-app
12
+ $ git init
13
+ $ git add .
14
+ $ git commit -m 'new rails app'
15
+ ```
16
+
17
+ 2. Create a new Heroku app
18
+ --------------------------
19
+
20
+ The next step is to create a new heroku app. Pull up your heroku dashboard and make a new app!
21
+
22
+ cli:
23
+ ```sh
24
+ $ heroku create name
25
+ $ heroku git:remote -a name
26
+ ```
27
+
28
+ now we need to let git know where the remote server is so we'll be able to deploy later
29
+
30
+ web:
31
+ ```sh
32
+ # https://dashboard.heroku.com/new
33
+ $ git remote add heroku git@heroku.com:appinfive.git
34
+ ```
35
+
36
+ 3. Contact Spiffy Stores to create app
37
+ --------------------------------------
38
+ You will be given the app credentials and the redirect_uri will be set to the required value.
39
+
40
+ * set the callback url to `https://<name>.herokuapp.com/`
41
+ * choose an embedded app
42
+ * set the redirect_uri to `https://<name>.herokuapp.com/auth/spiffy/callback`
43
+
44
+
45
+ 4. Add SpiffyStoresApp to gemfile
46
+ ----------------------------
47
+ ```sh
48
+ $ echo "gem 'spiffy_stores_app'" >> Gemfile
49
+ $ bundle install
50
+ ```
51
+
52
+ Note - its recommended to use the latest released version. Check the git tags to see the latest release and then add it to your Gemfile e.g `gem 'spiffy_stores_app', '~> 7.0.0'`
53
+
54
+ 5. Run the SpiffyStoresApp generator
55
+ ------------------------------------
56
+ ```sh
57
+ # use the keys for your app that have been provided to you
58
+ $ rails generate spiffy_stores_app --api_key <spiffy_stores_api_key> --secret <spiffy_stores_api_secret>
59
+ $ git add .
60
+ $ git commit -m 'generated spiffy stores app'
61
+ ```
62
+
63
+ If you forget to set your keys or redirect uri above, you will find them in the spiffy_stores_app initializer at: `/config/initializers/spiffy_stores_app.rb`.
64
+
65
+ We recommend adding a gem or utilizing ENV variables to handle your keys before releasing your app.
66
+
67
+ 6. Deploy
68
+ ---------
69
+ ```sh
70
+ $ git push heroku
71
+ $ heroku run rake db:migrate
72
+ ```
73
+
74
+ 7. Install the App!
75
+ -------------------
76
+ `https://<name>.herokuapp.com/`
@@ -0,0 +1,43 @@
1
+ require 'rails/generators/base'
2
+
3
+ module SpiffyStoresApp
4
+ module Generators
5
+ class AddAfterAuthenticateJobGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ hook_for :test_framework, as: :job, in: :rails do |instance, generator|
9
+ instance.invoke generator, [ instance.send(:job_file_name) ]
10
+ end
11
+
12
+ def init_after_authenticate_config
13
+ initializer = load_initializer
14
+
15
+ after_authenticate_job_config = " config.after_authenticate_job = { job: SpiffyStores::AfterAuthenticateJob, inline: false }\n"
16
+
17
+ inject_into_file(
18
+ 'config/initializers/spiffy_stores_app.rb',
19
+ after_authenticate_job_config,
20
+ before: 'end'
21
+ )
22
+
23
+ unless initializer.include?(after_authenticate_job_config)
24
+ shell.say "Error adding after_authneticate_job to config. Add this line manually: #{after_authenticate_job_config}", :red
25
+ end
26
+ end
27
+
28
+ def add_after_authenticate_job
29
+ template 'after_authenticate_job.rb', "app/jobs/#{job_file_name}_job.rb"
30
+ end
31
+
32
+ private
33
+
34
+ def load_initializer
35
+ File.read(File.join(destination_root, 'config/initializers/spiffy_stores_app.rb'))
36
+ end
37
+
38
+ def job_file_name
39
+ 'spiffy_stores/after_authenticate'
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,10 @@
1
+ module SpiffyStores
2
+ class AfterAuthenticateJob < ActiveJob::Base
3
+ def perform(shop_domain:)
4
+ shop = Shop.find_by(short_name: shop_domain)
5
+
6
+ shop.with_spiffy_stores_session do
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,68 @@
1
+ require 'rails/generators/base'
2
+
3
+ module SpiffyStoresApp
4
+ module Generators
5
+ class AddWebhookGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __FILE__)
7
+ class_option :topic, type: :string, aliases: "-t", required: true
8
+ class_option :address, type: :string, aliases: "-a", required: true
9
+
10
+ hook_for :test_framework, as: :job, in: :rails do |instance, generator|
11
+ instance.invoke generator, [ instance.send(:job_file_name) ]
12
+ end
13
+
14
+ def init_webhook_config
15
+ initializer = load_initializer
16
+ return if initializer.include?("config.webhooks")
17
+
18
+ inject_into_file(
19
+ 'config/initializers/spiffy_stores_app.rb',
20
+ " config.webhooks = [\n ]\n",
21
+ before: 'end'
22
+ )
23
+ end
24
+
25
+ def inject_webhook_to_spiffy_stores_app_initializer
26
+ inject_into_file(
27
+ 'config/initializers/spiffy_stores_app.rb',
28
+ webhook_config,
29
+ after: "config.webhooks = ["
30
+ )
31
+
32
+ initializer = load_initializer
33
+
34
+ unless initializer.include?(webhook_config)
35
+ shell.say "Error adding webhook to config. Add this line manually: #{webhook_config}", :red
36
+ end
37
+ end
38
+
39
+ def add_webhook_job
40
+ @job_file_name = job_file_name + '_job'
41
+ @job_class_name = @job_file_name.classify
42
+ template 'webhook_job.rb', "app/jobs/#{@job_file_name}.rb"
43
+ end
44
+
45
+ private
46
+
47
+ def job_file_name
48
+ address.split('/').last
49
+ end
50
+
51
+ def load_initializer
52
+ File.read(File.join(destination_root, 'config/initializers/spiffy_stores_app.rb'))
53
+ end
54
+
55
+ def webhook_config
56
+ "\n {topic: '#{topic}', address: '#{address}', format: 'json'},"
57
+ end
58
+
59
+ def topic
60
+ options['topic']
61
+ end
62
+
63
+ def address
64
+ options['address']
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,8 @@
1
+ class <%= @job_class_name %> < ActiveJob::Base
2
+ def perform(shop_domain:, webhook:)
3
+ shop = Shop.find_by(spiffy_stores_domain: shop_domain)
4
+
5
+ shop.with_spiffy_stores_session do
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,25 @@
1
+ require 'rails/generators/base'
2
+
3
+ module SpiffyStoresApp
4
+ module Generators
5
+ class AppProxyControllerGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ def create_app_proxy_controller
9
+ template 'app_proxy_controller.rb', 'app/controllers/app_proxy_controller.rb'
10
+ end
11
+
12
+ def create_app_proxy_index_view
13
+ copy_file 'index.html.erb', 'app/views/app_proxy/index.html.erb'
14
+ end
15
+
16
+ def add_app_proxy_route
17
+ inject_into_file(
18
+ 'config/routes.rb',
19
+ File.read(File.expand_path(find_in_source_paths('app_proxy_route.rb'))),
20
+ after: "mount SpiffyStoresApp::Engine, at: '/'\n"
21
+ )
22
+ end
23
+ end
24
+ end
25
+ end