shopify_app_lrb3 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/CHANGELOG +5 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +19 -0
  6. data/README.md +182 -0
  7. data/RELEASING +16 -0
  8. data/Rakefile +11 -0
  9. data/install.rb +25 -0
  10. data/lib/generators/shopify_app/README +23 -0
  11. data/lib/generators/shopify_app/USAGE +22 -0
  12. data/lib/generators/shopify_app/shopify_app_generator.rb +69 -0
  13. data/lib/generators/shopify_app/templates/app/assets/images/favicon.png +0 -0
  14. data/lib/generators/shopify_app/templates/app/assets/images/grid-18px.png +0 -0
  15. data/lib/generators/shopify_app/templates/app/assets/images/shopify-114.png +0 -0
  16. data/lib/generators/shopify_app/templates/app/assets/images/shopify-57.png +0 -0
  17. data/lib/generators/shopify_app/templates/app/assets/images/shopify-72.png +0 -0
  18. data/lib/generators/shopify_app/templates/app/assets/images/shopify.png +0 -0
  19. data/lib/generators/shopify_app/templates/app/assets/javascripts/application.js +15 -0
  20. data/lib/generators/shopify_app/templates/app/assets/stylesheets/application.css +10 -0
  21. data/lib/generators/shopify_app/templates/app/assets/stylesheets/imports.css.less +5 -0
  22. data/lib/generators/shopify_app/templates/app/assets/stylesheets/shopify_app.css.scss +150 -0
  23. data/lib/generators/shopify_app/templates/app/assets/stylesheets/shopify_app_buttons.css.less +77 -0
  24. data/lib/generators/shopify_app/templates/app/controllers/application_controller.rb +13 -0
  25. data/lib/generators/shopify_app/templates/app/controllers/home_controller.rb +18 -0
  26. data/lib/generators/shopify_app/templates/app/controllers/sessions_controller.rb +52 -0
  27. data/lib/generators/shopify_app/templates/app/helpers/home_helper.rb +9 -0
  28. data/lib/generators/shopify_app/templates/app/helpers/login_helper.rb +3 -0
  29. data/lib/generators/shopify_app/templates/app/helpers/tabs_helper.rb +11 -0
  30. data/lib/generators/shopify_app/templates/app/views/home/design.html.erb +3542 -0
  31. data/lib/generators/shopify_app/templates/app/views/home/index.html.erb +168 -0
  32. data/lib/generators/shopify_app/templates/app/views/home/welcome.html.erb +110 -0
  33. data/lib/generators/shopify_app/templates/app/views/layouts/application.html.erb +79 -0
  34. data/lib/generators/shopify_app/templates/app/views/sessions/new.html.erb +21 -0
  35. data/lib/generators/shopify_app/templates/config/initializers/omniauth.rb +14 -0
  36. data/lib/generators/shopify_app/templates/config/initializers/shopify_session_repository.rb +21 -0
  37. data/lib/generators/shopify_app/templates/public/404.html +40 -0
  38. data/lib/generators/shopify_app/templates/public/422.html +40 -0
  39. data/lib/generators/shopify_app/templates/public/500.html +40 -0
  40. data/lib/generators/shopify_app/templates/public/favicon.png +0 -0
  41. data/lib/generators/shopify_app/templates/public/shopify-114.png +0 -0
  42. data/lib/generators/shopify_app/templates/public/shopify-57.png +0 -0
  43. data/lib/generators/shopify_app/templates/public/shopify-72.png +0 -0
  44. data/lib/shopify_app.rb +20 -0
  45. data/lib/shopify_app/configuration.rb +46 -0
  46. data/lib/shopify_app/in_memory_session_store.rb +25 -0
  47. data/lib/shopify_app/login_protection.rb +39 -0
  48. data/lib/shopify_app/railtie.rb +17 -0
  49. data/lib/shopify_app/shopify_session_repository.rb +22 -0
  50. data/lib/shopify_app/version.rb +3 -0
  51. data/shipit.rubygems.yml +1 -0
  52. data/shopify_app.gemspec +30 -0
  53. data/test/config/development_config_file.yml +7 -0
  54. data/test/config/empty_config_file.yml +1 -0
  55. data/test/config/other_config_file.yml +3 -0
  56. data/test/config/shopify_app.yml +3 -0
  57. data/test/lib/shopify_app/configuration_test.rb +78 -0
  58. data/test/lib/shopify_app/in_memory_session_store_test.rb +35 -0
  59. data/test/lib/shopify_app/shopify_session_repository_test.rb +57 -0
  60. data/test/test_helper.rb +5 -0
  61. metadata +214 -0
@@ -0,0 +1,40 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>422 Error: Your change was rejected</title>
5
+
6
+ <style>
7
+ .container { text-align:center;}
8
+ .navbar .brand { float:none;}
9
+ </style>
10
+ </head>
11
+
12
+ <body>
13
+ <div class="navbar navbar-fixed-top">
14
+ <div class="navbar-inner">
15
+ <div class="container">
16
+ <a href="/" class="brand">Shopify Demo App</a>
17
+ </div>
18
+ </div>
19
+ </div>
20
+
21
+ <div class="container">
22
+ <div class="content">
23
+
24
+ <div class="page-header">
25
+ <h1>422 Error</h1>
26
+ </div>
27
+
28
+ <h3><i class="icon-warning-sign" style="margin-top:6px; opacity:.5;"></i> Sorry, the change you requested was rejected.</h3>
29
+ <p class="muted">Did you try to change something you don't have access to?</p>
30
+
31
+ <p><button type="button" value ="back" onClick="window.history.back();" class='btn btn-primary'><i class="icon-chevron-left" style="opacity:.25"></i> Back to the app</button></p>
32
+
33
+ </div>
34
+
35
+ <footer>
36
+ <p>A Shopify app by (company name here)</p>
37
+ </footer>
38
+ </div> <!-- /container -->
39
+ </body>
40
+ </html>
@@ -0,0 +1,40 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>500 Error: Something went horribly wrong</title>
5
+
6
+ <style>
7
+ .container { text-align:center;}
8
+ .navbar .brand { float:none;}
9
+ </style>
10
+ </head>
11
+
12
+ <body>
13
+ <div class="navbar navbar-fixed-top">
14
+ <div class="navbar-inner">
15
+ <div class="container">
16
+ <a href="/" class="brand">Shopify Demo App</a>
17
+ </div>
18
+ </div>
19
+ </div>
20
+
21
+ <div class="container">
22
+ <div class="content">
23
+
24
+ <div class="page-header">
25
+ <h1>AH! 500 Error!</h1>
26
+ </div>
27
+
28
+ <h3><i class="icon-warning-sign" style="margin-top:6px; opacity:.5;"></i> We're sorry, but something went wrong.</h3>
29
+ <p class="muted">The developer of this app has been notified.</p>
30
+
31
+ <p><button type="button" value ="back" onClick="window.history.back();" class='btn btn-primary'><i class="icon-chevron-left" style="opacity:.25"></i> Back to the app</button></p>
32
+
33
+ </div>
34
+
35
+ <footer>
36
+ <p>A Shopify app by (company name here)</p>
37
+ </footer>
38
+ </div> <!-- /container -->
39
+ </body>
40
+ </html>
@@ -0,0 +1,20 @@
1
+ require 'shopify_api'
2
+ require 'omniauth-shopify-oauth2'
3
+
4
+ module ShopifyApp
5
+
6
+ def self.configuration
7
+ @configuration ||= ShopifyApp::Configuration.new
8
+ end
9
+
10
+ def self.setup_session
11
+ ShopifyAPI::Session.setup(:api_key => ShopifyApp.configuration.api_key, :secret => ShopifyApp.configuration.secret)
12
+ end
13
+ end
14
+
15
+ require 'shopify_app/shopify_session_repository'
16
+ require 'shopify_app/in_memory_session_store'
17
+ require 'shopify_app/login_protection'
18
+ require 'shopify_app/configuration'
19
+ require 'shopify_app/railtie'
20
+ require 'shopify_app/version'
@@ -0,0 +1,46 @@
1
+ class ShopifyApp::Configuration
2
+ VALID_KEYS = [:api_key, :secret]
3
+ attr_writer *VALID_KEYS
4
+
5
+ def initialize(params={})
6
+ self.params = default_params.merge(params)
7
+ end
8
+
9
+ VALID_KEYS.each do |meth|
10
+ define_method meth do
11
+ meth = meth.to_s
12
+ config_from_env(meth) || config_from_rails(meth) || config_from_file(meth) || ''
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ attr_accessor :params
19
+
20
+ def config_from_env(meth)
21
+ ENV["SHOPIFY_APP_#{meth.upcase}"]
22
+ end
23
+
24
+ def config_from_rails(meth)
25
+ instance_variable_get("@#{meth}")
26
+ end
27
+
28
+ def config_from_file(meth)
29
+ @config_file ||= load_config
30
+ @config_file[Rails.env].try(:[], meth) || @config_file['common'].try(:[], meth)
31
+ end
32
+
33
+ def load_config
34
+ File.exist?(config_filepath) ? YAML.load_file(config_filepath) : {}
35
+ end
36
+
37
+ def config_filepath
38
+ params[:config_file]
39
+ end
40
+
41
+ def default_params
42
+ {
43
+ config_file: File.join(Rails.root, 'config', 'shopify_app.yml')
44
+ }
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ # WARNING - This really only works for development, see README for more details
2
+ class InMemorySessionStore
3
+ class EnvironmentError < StandardError; end
4
+
5
+ def self.retrieve(id)
6
+ repo[id]
7
+ end
8
+
9
+ def self.store(session)
10
+ id = SecureRandom.uuid
11
+ repo[id] = session
12
+ id
13
+ end
14
+
15
+ def self.clear
16
+ @@repo = nil
17
+ end
18
+
19
+ def self.repo
20
+ if Rails.env.production?
21
+ raise EnvironmentError.new("Cannot use InMemorySessionStore in a Production environment")
22
+ end
23
+ @@repo ||= {}
24
+ end
25
+ end
@@ -0,0 +1,39 @@
1
+ module ShopifyApp::LoginProtection
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ rescue_from ActiveResource::UnauthorizedAccess, :with => :close_session
6
+ end
7
+
8
+ def shopify_session
9
+ if shop_session
10
+ begin
11
+ # session[:shopify] set in LoginController#show
12
+ ShopifyAPI::Base.activate_session(shop_session)
13
+ yield
14
+ ensure
15
+ ShopifyAPI::Base.clear_session
16
+ end
17
+ else
18
+ session[:return_to] = request.fullpath if request.get?
19
+ redirect_to login_path(shop: params[:shop])
20
+ end
21
+ end
22
+
23
+ def shop_session
24
+ ShopifySessionRepository.retrieve(session[:shopify])
25
+ end
26
+
27
+ def login_again_if_different_shop
28
+ if shop_session && params[:shop] && params[:shop].is_a?(String) && shop_session.url != params[:shop]
29
+ redirect_to login_path(shop: params[:shop])
30
+ end
31
+ end
32
+
33
+ protected
34
+
35
+ def close_session
36
+ session[:shopify] = nil
37
+ redirect_to login_path
38
+ end
39
+ end
@@ -0,0 +1,17 @@
1
+ require 'rails'
2
+
3
+ class ShopifyApp::Railtie < ::Rails::Railtie
4
+
5
+ config.before_configuration do
6
+ config.shopify = ShopifyApp.configuration
7
+ end
8
+
9
+ initializer "shopify_app.action_controller_integration" do
10
+ ActionController::Base.send :include, ShopifyApp::LoginProtection
11
+ ActionController::Base.send :helper_method, :shop_session
12
+ end
13
+
14
+ initializer "shopify_app.setup_session" do
15
+ ShopifyApp.setup_session
16
+ end
17
+ end
@@ -0,0 +1,22 @@
1
+ class ShopifySessionRepository
2
+ class ConfigurationError < StandardError; end
3
+
4
+ def self.storage=(storage)
5
+ @@storage = storage
6
+ end
7
+
8
+ def self.retrieve(id)
9
+ validate
10
+ @@storage.retrieve(id)
11
+ end
12
+
13
+ def self.store(session)
14
+ validate
15
+ @@storage.store(session)
16
+ end
17
+
18
+ def self.validate
19
+ raise ConfigurationError.new("ShopifySessionRepository.store is not configured!") unless @@storage
20
+ end
21
+
22
+ end
@@ -0,0 +1,3 @@
1
+ module ShopifyApp
2
+ VERSION = "5.0.0"
3
+ end
@@ -0,0 +1 @@
1
+ # using the default shipit config
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "shopify_app/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "shopify_app_lrb3"
7
+ s.version = ShopifyApp::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.author = "Shopify"
10
+ s.email = ["gareth@bencrudo.com"]
11
+ s.homepage = "http://www.shopify.com/developers"
12
+ s.summary = %q{Fork of shopify_app upgrade to Less Rails Bootstrap 3.1.1}
13
+ s.description = %q{Required Boostrap 3 so cloned and upgraded to Less Rails Bootstrap 3.1.1}
14
+
15
+ s.rubyforge_project = "shopify-api"
16
+
17
+ s.add_runtime_dependency('rails', '>= 3.1', '< 5.0')
18
+ s.add_runtime_dependency('shopify_api', '~> 3.2.0')
19
+ s.add_runtime_dependency('omniauth-shopify-oauth2', '~> 1.1.4')
20
+ s.add_runtime_dependency('less-rails-bootstrap', '~> 3.1.1')
21
+
22
+ s.add_development_dependency('rake')
23
+ s.add_development_dependency('minitest')
24
+ s.add_development_dependency('mocha')
25
+
26
+ s.files = `git ls-files`.split("\n")
27
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
28
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
29
+ s.require_paths = ["lib"]
30
+ end
@@ -0,0 +1,7 @@
1
+ common:
2
+ api_key: should never see this api key value
3
+ secret: should never see this secret value
4
+
5
+ development:
6
+ api_key: development key
7
+ secret: development secret
@@ -0,0 +1 @@
1
+ common:
@@ -0,0 +1,3 @@
1
+ common:
2
+ api_key: api key from other file
3
+ secret: secret from other file
@@ -0,0 +1,3 @@
1
+ common:
2
+ api_key: api key from default file
3
+ secret: secret from default file
@@ -0,0 +1,78 @@
1
+ require 'test_helper'
2
+
3
+ class ConfigurationTest < Minitest::Test
4
+ def setup
5
+ Rails.stubs(:env).returns('development')
6
+ Rails.stubs(:root).returns(File.expand_path('../..', File.dirname(__FILE__)))
7
+ end
8
+
9
+ def config_file(filename)
10
+ filepath = File.expand_path("../../config/#{filename}", File.dirname(__FILE__))
11
+ end
12
+
13
+ def test_define_method_creates_readers
14
+ config = ShopifyApp::Configuration.new
15
+ config.respond_to?(:api_key)
16
+ config.respond_to?(:secret)
17
+ end
18
+
19
+ def test_defaults_to_empty_string
20
+ config = ShopifyApp::Configuration.new(config_file: config_file('empty_config_file.yml'))
21
+
22
+ assert_equal '', config.api_key
23
+ assert_equal '', config.secret
24
+ end
25
+
26
+ def test_environment_has_precedence_over_common
27
+ config = ShopifyApp::Configuration.new(config_file: config_file('development_config_file.yml'))
28
+
29
+ assert_equal 'development key', config.api_key
30
+ assert_equal 'development secret', config.secret
31
+ end
32
+
33
+ def test_rails_has_precedence_over_environment
34
+ config = ShopifyApp::Configuration.new(config_file: config_file('development_config_file.yml'))
35
+
36
+ assert_equal 'development key', config.api_key
37
+ assert_equal 'development secret', config.secret
38
+
39
+ config.api_key = 'rails key'
40
+ config.secret = 'rails secret'
41
+
42
+ assert_equal 'rails key', config.api_key
43
+ assert_equal 'rails secret', config.secret
44
+ end
45
+
46
+ def test_env_has_precedence_over_rails
47
+ config = ShopifyApp::Configuration.new
48
+ config.api_key = 'rails key'
49
+ config.secret = 'rails secret'
50
+
51
+ assert_equal 'rails key', config.api_key
52
+ assert_equal 'rails secret', config.secret
53
+
54
+ ENV.expects(:[]).with('SHOPIFY_APP_API_KEY').returns('env key')
55
+ ENV.expects(:[]).with('SHOPIFY_APP_SECRET').returns('env secret')
56
+
57
+ assert_equal 'env key', config.api_key
58
+ assert_equal 'env secret', config.secret
59
+ end
60
+
61
+ def test_reads_config_from_default_config_file
62
+ config = ShopifyApp::Configuration.new
63
+ assert_equal 'api key from default file', config.api_key
64
+ assert_equal 'secret from default file', config.secret
65
+ end
66
+
67
+ def test_reads_config_from_specified_config_file
68
+ config = ShopifyApp::Configuration.new(config_file: config_file('other_config_file.yml'))
69
+ assert_equal 'api key from other file', config.api_key
70
+ assert_equal 'secret from other file', config.secret
71
+ end
72
+
73
+ def test_handles_missing_config_file
74
+ config = ShopifyApp::Configuration.new(config_file: config_file('missing_config_file.yml'))
75
+ assert_equal '', config.api_key
76
+ assert_equal '', config.secret
77
+ end
78
+ end
@@ -0,0 +1,35 @@
1
+ require 'test_helper'
2
+
3
+ class InMemorySessionStoreTest < Minitest::Test
4
+ def teardown
5
+ InMemorySessionStore.clear
6
+ end
7
+
8
+ def test_storing_a_session
9
+ uuid = InMemorySessionStore.store('something')
10
+ assert_equal 'something', InMemorySessionStore.repo[uuid]
11
+ end
12
+
13
+ def test_retrieving_a_session
14
+ InMemorySessionStore.repo['abra'] = 'something'
15
+ assert_equal 'something', InMemorySessionStore.retrieve('abra')
16
+ end
17
+
18
+ def test_clearing_the_store
19
+ uuid = InMemorySessionStore.store('data')
20
+ assert_equal 'data', InMemorySessionStore.retrieve(uuid)
21
+ InMemorySessionStore.clear
22
+ assert !InMemorySessionStore.retrieve(uuid), 'The sessions should have been removed'
23
+ end
24
+
25
+ def test_it_should_raise_when_the_environment_is_not_valid
26
+ Rails.env.stubs(:production?).returns(true)
27
+ assert_raises InMemorySessionStore::EnvironmentError do
28
+ InMemorySessionStore.store('data')
29
+ end
30
+
31
+ assert_raises InMemorySessionStore::EnvironmentError do
32
+ InMemorySessionStore.retrieve('abracadabra')
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,57 @@
1
+ require 'test_helper'
2
+
3
+ class TestSessionStore
4
+ attr_reader :storage
5
+ def initialize
6
+ @storage = []
7
+ end
8
+
9
+ def retrieve(id)
10
+ storage[id]
11
+ end
12
+
13
+ def store(session)
14
+ id = storage.length
15
+ storage[id] = session
16
+ id
17
+ end
18
+ end
19
+
20
+ class ShopifySessionRepositoryTest < Minitest::Test
21
+ attr_reader :session_store, :session
22
+ def setup
23
+ @session_store = TestSessionStore.new
24
+ @session = ShopifyAPI::Session.new('shop.myshopify.com', 'abracadabra')
25
+ ShopifySessionRepository.storage = session_store
26
+ end
27
+
28
+ def teardown
29
+ ShopifySessionRepository.storage = nil
30
+ end
31
+
32
+ def test_adding_a_session_to_the_repository
33
+ assert_equal 0, ShopifySessionRepository.store(session)
34
+ assert_equal session, session_store.retrieve(0)
35
+ end
36
+
37
+ def test_retrieving_a_session_from_the_repository
38
+ session_store.storage[9] = session
39
+ assert_equal session, ShopifySessionRepository.retrieve(9)
40
+ end
41
+
42
+ def test_retrieving_a_session_for_an_id_that_does_not_exist
43
+ ShopifySessionRepository.store(session)
44
+ assert !ShopifySessionRepository.retrieve(100), "The session with id 100 should not exist in the Repository"
45
+ end
46
+
47
+ def test_retrieving_a_session_for_a_misconfigured_shops_repository
48
+ ShopifySessionRepository.storage = nil
49
+ assert_raises ShopifySessionRepository::ConfigurationError do
50
+ ShopifySessionRepository.retrieve(0)
51
+ end
52
+
53
+ assert_raises ShopifySessionRepository::ConfigurationError do
54
+ ShopifySessionRepository.store(session)
55
+ end
56
+ end
57
+ end