refinerycms-api 1.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.rbenv-gemsets +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +12 -0
- data/Gemfile +57 -0
- data/LICENSE +27 -0
- data/Rakefile +21 -0
- data/app/controllers/refinery/api/base_controller.rb +174 -0
- data/app/controllers/refinery/api/v1/blog/posts_controller.rb +78 -0
- data/app/controllers/refinery/api/v1/images_controller.rb +76 -0
- data/app/controllers/refinery/api/v1/inquiries/inquiries_controller.rb +69 -0
- data/app/controllers/refinery/api/v1/pages_controller.rb +77 -0
- data/app/controllers/refinery/api/v1/resources_controller.rb +66 -0
- data/app/decorators/models/refinery/authentication/devise/user_decorator.rb +5 -0
- data/app/helpers/refinery/api/api_helpers.rb +54 -0
- data/app/models/concerns/refinery/user_api_authentication.rb +19 -0
- data/app/models/refinery/ability.rb +59 -0
- data/app/views/refinery/api/errors/gateway_error.v1.rabl +2 -0
- data/app/views/refinery/api/errors/invalid_api_key.v1.rabl +2 -0
- data/app/views/refinery/api/errors/invalid_resource.v1.rabl +3 -0
- data/app/views/refinery/api/errors/must_specify_api_key.v1.rabl +2 -0
- data/app/views/refinery/api/errors/not_found.v1.rabl +2 -0
- data/app/views/refinery/api/errors/unauthorized.v1.rabl +2 -0
- data/app/views/refinery/api/v1/blog/posts/index.v1.rabl +5 -0
- data/app/views/refinery/api/v1/blog/posts/new.v1.rabl +3 -0
- data/app/views/refinery/api/v1/blog/posts/show.v1.rabl +5 -0
- data/app/views/refinery/api/v1/images/index.v1.rabl +5 -0
- data/app/views/refinery/api/v1/images/new.v1.rabl +3 -0
- data/app/views/refinery/api/v1/images/show.v1.rabl +6 -0
- data/app/views/refinery/api/v1/inquiries/inquiries/index.v1.rabl +5 -0
- data/app/views/refinery/api/v1/inquiries/inquiries/new.v1.rabl +3 -0
- data/app/views/refinery/api/v1/inquiries/inquiries/show.v1.rabl +5 -0
- data/app/views/refinery/api/v1/pages/index.v1.rabl +8 -0
- data/app/views/refinery/api/v1/pages/new.v1.rabl +3 -0
- data/app/views/refinery/api/v1/pages/pages.v1.rabl +5 -0
- data/app/views/refinery/api/v1/pages/show.v1.rabl +9 -0
- data/app/views/refinery/api/v1/resources/index.v1.rabl +5 -0
- data/app/views/refinery/api/v1/resources/new.v1.rabl +3 -0
- data/app/views/refinery/api/v1/resources/show.v1.rabl +6 -0
- data/bin/rails +5 -0
- data/bin/rake +21 -0
- data/bin/rspec +22 -0
- data/bin/spring +18 -0
- data/config/initializers/metal_load_paths.rb +1 -0
- data/config/locales/en.yml +27 -0
- data/config/routes.rb +24 -0
- data/db/migrate/20160501141738_add_api_key_to_refinery_authentication_devise_users.rb +8 -0
- data/lib/generators/refinery/api/api_generator.rb +16 -0
- data/lib/generators/refinery/api/templates/config/initializers/refinery/api.rb.erb +7 -0
- data/lib/refinery/api.rb +29 -0
- data/lib/refinery/api/configuration.rb +32 -0
- data/lib/refinery/api/controller_helpers/auth.rb +76 -0
- data/lib/refinery/api/controller_helpers/strong_parameters.rb +37 -0
- data/lib/refinery/api/controller_setup.rb +20 -0
- data/lib/refinery/api/engine.rb +52 -0
- data/lib/refinery/api/responders.rb +11 -0
- data/lib/refinery/api/responders/rabl_template.rb +30 -0
- data/lib/refinery/api/testing_support/caching.rb +10 -0
- data/lib/refinery/api/testing_support/helpers.rb +44 -0
- data/lib/refinery/api/testing_support/setup.rb +16 -0
- data/lib/refinery/permitted_attributes.rb +40 -0
- data/lib/refinery/responder.rb +45 -0
- data/lib/refinerycms-api.rb +3 -0
- data/readme.md +69 -0
- data/refinerycms_api.gemspec +22 -0
- data/script/rails +9 -0
- data/spec/controllers/refinery/api/base_controller_spec.rb +73 -0
- data/spec/controllers/refinery/api/v1/blog/posts_controller_spec.rb +140 -0
- data/spec/controllers/refinery/api/v1/images_controller_spec.rb +93 -0
- data/spec/controllers/refinery/api/v1/inquiries/inquiries_controller_spec.rb +126 -0
- data/spec/controllers/refinery/api/v1/pages_controller_spec.rb +150 -0
- data/spec/controllers/refinery/api/v1/resources_controller_spec.rb +94 -0
- data/spec/fixtures/refinery_is_awesome.txt +1 -0
- data/spec/fixtures/thinking-cat.jpg +0 -0
- data/spec/models/refinery/user_spec.rb +23 -0
- data/spec/requests/rabl_cache_spec.rb +17 -0
- data/spec/requests/ransackable_attributes_spec.rb +80 -0
- data/spec/requests/version_spec.rb +23 -0
- data/spec/shared_examples/protect_product_actions.rb +17 -0
- data/spec/spec_helper.rb +77 -0
- data/spec/support/controller_hacks.rb +33 -0
- data/spec/support/database_cleaner.rb +14 -0
- data/spec/support/have_attributes_matcher.rb +9 -0
- data/tasks/refinery_api.rake +14 -0
- data/tasks/rspec.rake +4 -0
- metadata +240 -0
data/bin/rails
ADDED
data/bin/rake
ADDED
@@ -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')
|
data/bin/rspec
ADDED
@@ -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')
|
data/bin/spring
ADDED
@@ -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."
|
data/config/routes.rb
ADDED
@@ -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
|
data/lib/refinery/api.rb
ADDED
@@ -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
|