refinerycms-api 1.0.0.beta

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 (87) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rbenv-gemsets +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +12 -0
  6. data/Gemfile +57 -0
  7. data/LICENSE +27 -0
  8. data/Rakefile +21 -0
  9. data/app/controllers/refinery/api/base_controller.rb +174 -0
  10. data/app/controllers/refinery/api/v1/blog/posts_controller.rb +78 -0
  11. data/app/controllers/refinery/api/v1/images_controller.rb +76 -0
  12. data/app/controllers/refinery/api/v1/inquiries/inquiries_controller.rb +69 -0
  13. data/app/controllers/refinery/api/v1/pages_controller.rb +77 -0
  14. data/app/controllers/refinery/api/v1/resources_controller.rb +66 -0
  15. data/app/decorators/models/refinery/authentication/devise/user_decorator.rb +5 -0
  16. data/app/helpers/refinery/api/api_helpers.rb +54 -0
  17. data/app/models/concerns/refinery/user_api_authentication.rb +19 -0
  18. data/app/models/refinery/ability.rb +59 -0
  19. data/app/views/refinery/api/errors/gateway_error.v1.rabl +2 -0
  20. data/app/views/refinery/api/errors/invalid_api_key.v1.rabl +2 -0
  21. data/app/views/refinery/api/errors/invalid_resource.v1.rabl +3 -0
  22. data/app/views/refinery/api/errors/must_specify_api_key.v1.rabl +2 -0
  23. data/app/views/refinery/api/errors/not_found.v1.rabl +2 -0
  24. data/app/views/refinery/api/errors/unauthorized.v1.rabl +2 -0
  25. data/app/views/refinery/api/v1/blog/posts/index.v1.rabl +5 -0
  26. data/app/views/refinery/api/v1/blog/posts/new.v1.rabl +3 -0
  27. data/app/views/refinery/api/v1/blog/posts/show.v1.rabl +5 -0
  28. data/app/views/refinery/api/v1/images/index.v1.rabl +5 -0
  29. data/app/views/refinery/api/v1/images/new.v1.rabl +3 -0
  30. data/app/views/refinery/api/v1/images/show.v1.rabl +6 -0
  31. data/app/views/refinery/api/v1/inquiries/inquiries/index.v1.rabl +5 -0
  32. data/app/views/refinery/api/v1/inquiries/inquiries/new.v1.rabl +3 -0
  33. data/app/views/refinery/api/v1/inquiries/inquiries/show.v1.rabl +5 -0
  34. data/app/views/refinery/api/v1/pages/index.v1.rabl +8 -0
  35. data/app/views/refinery/api/v1/pages/new.v1.rabl +3 -0
  36. data/app/views/refinery/api/v1/pages/pages.v1.rabl +5 -0
  37. data/app/views/refinery/api/v1/pages/show.v1.rabl +9 -0
  38. data/app/views/refinery/api/v1/resources/index.v1.rabl +5 -0
  39. data/app/views/refinery/api/v1/resources/new.v1.rabl +3 -0
  40. data/app/views/refinery/api/v1/resources/show.v1.rabl +6 -0
  41. data/bin/rails +5 -0
  42. data/bin/rake +21 -0
  43. data/bin/rspec +22 -0
  44. data/bin/spring +18 -0
  45. data/config/initializers/metal_load_paths.rb +1 -0
  46. data/config/locales/en.yml +27 -0
  47. data/config/routes.rb +24 -0
  48. data/db/migrate/20160501141738_add_api_key_to_refinery_authentication_devise_users.rb +8 -0
  49. data/lib/generators/refinery/api/api_generator.rb +16 -0
  50. data/lib/generators/refinery/api/templates/config/initializers/refinery/api.rb.erb +7 -0
  51. data/lib/refinery/api.rb +29 -0
  52. data/lib/refinery/api/configuration.rb +32 -0
  53. data/lib/refinery/api/controller_helpers/auth.rb +76 -0
  54. data/lib/refinery/api/controller_helpers/strong_parameters.rb +37 -0
  55. data/lib/refinery/api/controller_setup.rb +20 -0
  56. data/lib/refinery/api/engine.rb +52 -0
  57. data/lib/refinery/api/responders.rb +11 -0
  58. data/lib/refinery/api/responders/rabl_template.rb +30 -0
  59. data/lib/refinery/api/testing_support/caching.rb +10 -0
  60. data/lib/refinery/api/testing_support/helpers.rb +44 -0
  61. data/lib/refinery/api/testing_support/setup.rb +16 -0
  62. data/lib/refinery/permitted_attributes.rb +40 -0
  63. data/lib/refinery/responder.rb +45 -0
  64. data/lib/refinerycms-api.rb +3 -0
  65. data/readme.md +69 -0
  66. data/refinerycms_api.gemspec +22 -0
  67. data/script/rails +9 -0
  68. data/spec/controllers/refinery/api/base_controller_spec.rb +73 -0
  69. data/spec/controllers/refinery/api/v1/blog/posts_controller_spec.rb +140 -0
  70. data/spec/controllers/refinery/api/v1/images_controller_spec.rb +93 -0
  71. data/spec/controllers/refinery/api/v1/inquiries/inquiries_controller_spec.rb +126 -0
  72. data/spec/controllers/refinery/api/v1/pages_controller_spec.rb +150 -0
  73. data/spec/controllers/refinery/api/v1/resources_controller_spec.rb +94 -0
  74. data/spec/fixtures/refinery_is_awesome.txt +1 -0
  75. data/spec/fixtures/thinking-cat.jpg +0 -0
  76. data/spec/models/refinery/user_spec.rb +23 -0
  77. data/spec/requests/rabl_cache_spec.rb +17 -0
  78. data/spec/requests/ransackable_attributes_spec.rb +80 -0
  79. data/spec/requests/version_spec.rb +23 -0
  80. data/spec/shared_examples/protect_product_actions.rb +17 -0
  81. data/spec/spec_helper.rb +77 -0
  82. data/spec/support/controller_hacks.rb +33 -0
  83. data/spec/support/database_cleaner.rb +14 -0
  84. data/spec/support/have_attributes_matcher.rb +9 -0
  85. data/tasks/refinery_api.rake +14 -0
  86. data/tasks/rspec.rake +4 -0
  87. metadata +240 -0
@@ -0,0 +1,3 @@
1
+ object false
2
+ node(:attributes) { [*page_attributes] }
3
+ node(:required_attributes) { required_fields_for(Refinery::Page) }
@@ -0,0 +1,5 @@
1
+ attributes *page_attributes
2
+
3
+ node :pages do |t|
4
+ t.children.map { |c| partial("refinery/api/v1/pages/pages", :object => c) }
5
+ end
@@ -0,0 +1,9 @@
1
+ object @page
2
+
3
+ cache [I18n.locale, 'show', root_object]
4
+
5
+ attributes *page_attributes
6
+
7
+ child :parts => :page_parts do
8
+ attributes *page_part_attributes
9
+ end
@@ -0,0 +1,5 @@
1
+ object false
2
+ node(:count) { @resources.count }
3
+ child(@resources => :resources) do
4
+ extends "refinery/api/v1/resources/show"
5
+ end
@@ -0,0 +1,3 @@
1
+ object false
2
+ node(:attributes) { [*resource_attributes] }
3
+ node(:required_attributes) { required_fields_for(Refinery::Resource) }
@@ -0,0 +1,6 @@
1
+ object @resource
2
+ attributes :resource_title
3
+
4
+ node :file do |file|
5
+ file.file.url
6
+ end
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ ENGINE_PATH = File.expand_path('../..', __FILE__)
5
+ load File.expand_path('../../spec/dummy/bin/rails', __FILE__)
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+ begin
9
+ if Dir.exist?(File.expand_path('../../spec/dummy', __FILE__))
10
+ load File.expand_path("../spring", __FILE__)
11
+ end
12
+ rescue LoadError
13
+ end
14
+ require 'pathname'
15
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
16
+ Pathname.new(__FILE__).realpath)
17
+
18
+ require 'rubygems'
19
+ require 'bundler/setup'
20
+
21
+ load Gem.bin_path('rake', 'rake')
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rspec' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ begin
10
+ if Dir.exist?(File.expand_path('../../spec/dummy', __FILE__))
11
+ load File.expand_path("../spring", __FILE__)
12
+ end
13
+ rescue LoadError
14
+ end
15
+ require 'pathname'
16
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
17
+ Pathname.new(__FILE__).realpath)
18
+
19
+ require 'rubygems'
20
+ require 'bundler/setup'
21
+
22
+ load Gem.bin_path('rspec-core', 'rspec')
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This file loads spring without using Bundler, in order to be fast
4
+ # It gets overwritten when you run the `spring binstub` command
5
+
6
+ unless defined?(Spring)
7
+ require "rubygems"
8
+ require "bundler"
9
+
10
+ if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)
11
+ ENV["GEM_PATH"] = ([Bundler.bundle_path.to_s] + Gem.path).join(File::PATH_SEPARATOR)
12
+ ENV["GEM_HOME"] = ""
13
+ Gem.paths = ENV
14
+
15
+ gem "spring", match[1]
16
+ require "spring/binstub"
17
+ end
18
+ end
@@ -0,0 +1 @@
1
+ Refinery::Api::BaseController.append_view_path(ApplicationController.view_paths)
@@ -0,0 +1,27 @@
1
+ en:
2
+ refinery:
3
+ api:
4
+ must_specify_api_key: "You must specify an API key."
5
+ invalid_api_key: "Invalid API key (%{key}) specified."
6
+ unauthorized: "You are not authorized to perform that action."
7
+ invalid_resource: "Invalid resource. Please fix errors and try again."
8
+ resource_not_found: "The resource you were looking for could not be found."
9
+ gateway_error: "There was a problem with the payment gateway: %{text}"
10
+ access: "API Access"
11
+ key: "Key"
12
+ clear_key: "Clear key"
13
+ regenerate_key: "Regenerate Key"
14
+ no_key: "No key"
15
+ generate_key: "Generate API key"
16
+ key_generated: "Key generated"
17
+ key_cleared: "Key cleared"
18
+ order:
19
+ could_not_transition: "The order could not be transitioned. Please fix the errors and try again."
20
+ invalid_shipping_method: "Invalid shipping method specified."
21
+ payment:
22
+ credit_over_limit: "This payment can only be credited up to %{limit}. Please specify an amount less than or equal to this number."
23
+ update_forbidden: "This payment cannot be updated because it is %{state}."
24
+ shipment:
25
+ cannot_ready: "Cannot ready shipment."
26
+ stock_location_required: "A stock_location_id parameter must be provided in order to retrieve stock movements."
27
+ invalid_taxonomy_id: "Invalid taxonomy id."
@@ -0,0 +1,24 @@
1
+ Refinery::Core::Engine.routes.draw do
2
+ namespace :api, defaults: { format: 'json' } do
3
+ namespace :v1 do
4
+ resources :images
5
+
6
+ resources :pages do
7
+ resources :page_parts
8
+ end
9
+
10
+ resources :resources
11
+
12
+ namespace :blog do
13
+ resources :posts
14
+ end
15
+
16
+ namespace :inquiries do
17
+ resources :inquiries, only: [:new, :create, :index, :show, :destroy]
18
+ end
19
+ end
20
+
21
+ match 'v:api/*path', to: redirect("/api/v1/%{path}"), via: [:get, :post, :put, :patch, :delete]
22
+ match '*path', to: redirect("/api/v1/%{path}"), via: [:get, :post, :put, :patch, :delete]
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ class AddApiKeyToRefineryAuthenticationDeviseUsers < ActiveRecord::Migration
2
+ def change
3
+ unless defined?(User)
4
+ add_column :refinery_authentication_devise_users, :refinery_api_key, :string, limit: 48
5
+ add_index :refinery_authentication_devise_users, :refinery_api_key
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,16 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/base'
3
+
4
+ module Refinery
5
+ class ApiGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ def rake_db
9
+ rake "refinery_api:install:migrations"
10
+ end
11
+
12
+ def generate_api_initializer
13
+ template 'config/initializers/refinery/api.rb.erb', File.join(destination_root, 'config', 'initializers', 'refinery', 'api.rb')
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ Refinery::Api.configure do |config|
2
+ # Requires authentication to access API
3
+ # config.requires_authentication = <%= Refinery::Api.requires_authentication.inspect %>
4
+
5
+ # If you're grafting onto an existing app, change this to your User class
6
+ # config.user_class = <%= Refinery::Api.user_class.to_s.inspect %>
7
+ end
@@ -0,0 +1,29 @@
1
+ require 'refinerycms-core'
2
+ require 'cancan'
3
+ require 'responders'
4
+ require 'rabl'
5
+
6
+ module Refinery
7
+ autoload :ApiGenerator, 'generators/refinery/api/api_generator'
8
+
9
+ module Api
10
+ require 'refinery/api/engine'
11
+ require 'refinery/api/configuration'
12
+
13
+ autoload :Version, 'refinery/api/version'
14
+
15
+ class GatewayError < RuntimeError; end
16
+
17
+ class << self
18
+ attr_writer :root
19
+
20
+ def root
21
+ @root ||= Pathname.new(File.expand_path('../../../', __FILE__))
22
+ end
23
+
24
+ def factory_paths
25
+ @factory_paths ||= [ root.join("spec/factories").to_s ]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,32 @@
1
+ module Refinery
2
+ module Api
3
+ include ActiveSupport::Configurable
4
+
5
+ config_accessor :requires_authentication
6
+
7
+ self.requires_authentication = true
8
+
9
+ # Refinery::User isn't available when this line gets hit, so we use static methods instead
10
+ @@user_class_name = nil
11
+ class << self
12
+ def user_class=(class_name)
13
+ if class_name.is_a?(Class)
14
+ raise TypeError, "You can't set user_class to be a class, e.g., User. Instead, please use a string like 'User'"
15
+ elsif class_name.is_a?(String)
16
+ @@user_class_name = class_name
17
+ else
18
+ raise TypeError, "Invalid type for user_class. Please use a string like 'User'"
19
+ end
20
+ end
21
+
22
+ def user_class
23
+ class_name = @@user_class_name || "Refinery::Authentication::Devise::User"
24
+ begin
25
+ Object.const_get(class_name)
26
+ rescue NameError
27
+ class_name.constantize
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,76 @@
1
+ module Refinery
2
+ module Api
3
+ module ControllerHelpers
4
+ module Auth
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ helper_method :try_refinery_current_user
9
+
10
+ rescue_from CanCan::AccessDenied do |exception|
11
+ redirect_unauthorized_access
12
+ end
13
+ end
14
+
15
+ # Needs to be overriden so that we use Refinery's Ability rather than anyone else's.
16
+ def current_ability
17
+ @current_ability ||= Refinery::Ability.new(try_refinery_current_user)
18
+ end
19
+
20
+ def redirect_back_or_default(default)
21
+ redirect_to(session["refinery_user_return_to"] || request.env["HTTP_REFERER"] || default)
22
+ session["refinery_user_return_to"] = nil
23
+ end
24
+
25
+ def store_location
26
+ # disallow return to login, logout, signup pages
27
+ authentication_routes = [:refinery_signup_path, :refinery_login_path, :refinery_logout_path]
28
+ disallowed_urls = []
29
+ authentication_routes.each do |route|
30
+ if respond_to?(route)
31
+ disallowed_urls << send(route)
32
+ end
33
+ end
34
+
35
+ disallowed_urls.map!{ |url| url[/\/\w+$/] }
36
+ unless disallowed_urls.include?(request.fullpath)
37
+ session['refinery_user_return_to'] = request.fullpath.gsub('//', '/')
38
+ end
39
+ end
40
+
41
+ # proxy method to *possible* refinery_current_user method
42
+ # Authentication extensions (such as refinery_auth_devise) are meant to provide refinery_current_user
43
+ def try_refinery_current_user
44
+ # This one will be defined by apps looking to hook into Refinery
45
+ # As per authentication_helpers.rb
46
+ if respond_to?(:refinery_current_user)
47
+ refinery_current_user
48
+ # This one will be defined by Devise
49
+ elsif respond_to?(:current_refinery_user)
50
+ current_refinery_user
51
+ else
52
+ nil
53
+ end
54
+ end
55
+
56
+ # Redirect as appropriate when an access request fails. The default action is to redirect to the login screen.
57
+ # Override this method in your controllers if you want to have special behavior in case the user is not authorized
58
+ # to access the requested action. For example, a popup window might simply close itself.
59
+ def redirect_unauthorized_access
60
+ if try_refinery_current_user
61
+ flash[:error] = Refinery.t(:authorization_failure)
62
+ redirect_to refinery.forbidden_path
63
+ else
64
+ store_location
65
+ if respond_to?(:refinery_login_path)
66
+ redirect_to refinery_login_path
67
+ else
68
+ redirect_to refinery.respond_to?(:root_path) ? refinery.root_path : main_app.root_path
69
+ end
70
+ end
71
+ end
72
+
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,37 @@
1
+ module Refinery
2
+ module Api
3
+ module ControllerHelpers
4
+ module StrongParameters
5
+ def permitted_attributes
6
+ Refinery::PermittedAttributes
7
+ end
8
+
9
+ delegate *Refinery::PermittedAttributes::ATTRIBUTES,
10
+ to: :permitted_attributes,
11
+ prefix: :permitted
12
+
13
+ def permitted_image_attributes
14
+ permitted_attributes.image_attributes
15
+ end
16
+
17
+ def permitted_page_attributes
18
+ permitted_attributes.page_attributes + [
19
+ page_parts_attributes: permitted_page_part_attributes
20
+ ]
21
+ end
22
+
23
+ def permitted_resource_attributes
24
+ permitted_attributes.resource_attributes
25
+ end
26
+
27
+ def permitted_blog_post_attributes
28
+ permitted_attributes.blog_post_attributes
29
+ end
30
+
31
+ def permitted_inquiries_inquiry_attributes
32
+ permitted_attributes.inquiries_inquiry_attributes
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,20 @@
1
+ require 'refinery/api/responders'
2
+
3
+ module Refinery
4
+ module Api
5
+ module ControllerSetup
6
+ def self.included(klass)
7
+ klass.class_eval do
8
+ include CanCan::ControllerAdditions
9
+ include Refinery::Api::ControllerHelpers::Auth
10
+
11
+ prepend_view_path Rails.root + "app/views"
12
+ append_view_path File.expand_path("../../../app/views", File.dirname(__FILE__))
13
+
14
+ self.responder = Refinery::Api::Responders::AppResponder
15
+ respond_to :json
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,52 @@
1
+ require 'versioncake'
2
+
3
+ module Refinery
4
+ module Api
5
+ class Engine < Rails::Engine
6
+ include Refinery::Engine
7
+
8
+ isolate_namespace Refinery::Api
9
+ engine_name :refinery_api
10
+
11
+ config.autoload_paths += %W( #{config.root}/lib )
12
+
13
+ config.before_configuration do
14
+ ::Rabl.configure do |config|
15
+ config.include_json_root = false
16
+ config.include_child_root = false
17
+
18
+ # Motivation here it make it call as_json when rendering timestamps
19
+ # and therefore display miliseconds. Otherwise it would fall to
20
+ # JSON.dump which doesn't display the miliseconds
21
+ config.json_engine = ActiveSupport::JSON
22
+ end
23
+
24
+ config.versioncake.supported_version_numbers = [1]
25
+ config.versioncake.extraction_strategy = :http_header
26
+ end
27
+
28
+ config.after_initialize do
29
+ Refinery.register_engine(Refinery::Api)
30
+ end
31
+
32
+ # initializer "refinery.api.environment", :before => :load_config_initializers do |app|
33
+ # # Refinery::Api::Config = Refinery::ApiConfiguration.new
34
+ # end
35
+
36
+ # def self.activate
37
+ # Dir.glob(File.join(File.dirname(__FILE__), "../../../app/**/*_decorator*.rb")) do |c|
38
+ # Rails.configuration.cache_classes ? require(c) : load(c)
39
+ # end
40
+ # end
41
+ # config.to_prepare &method(:activate).to_proc
42
+
43
+ config.to_prepare do
44
+ Decorators.register! ::Refinery::Api.root
45
+ end
46
+
47
+ # def self.root
48
+ # @root ||= Pathname.new(File.expand_path('../../../../', __FILE__))
49
+ # end
50
+ end
51
+ end
52
+ end