spiffy_stores_app 8.2.6

Sign up to get free protection for your applications and to get access to all the features.
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