introspective_grape 0.6.1 → 0.7.0
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +85 -84
- data/.ruby-version +1 -1
- data/CHANGELOG.md +10 -0
- data/Gemfile +38 -22
- data/README.md +13 -20
- data/introspective_grape.gemspec +41 -64
- data/lib/introspective_grape/api.rb +469 -461
- data/lib/introspective_grape/camel_snake.rb +3 -3
- data/lib/introspective_grape/create_helpers.rb +25 -25
- data/lib/introspective_grape/filters.rb +5 -3
- data/lib/introspective_grape/route.rb +11 -0
- data/lib/introspective_grape/traversal.rb +56 -56
- data/lib/introspective_grape/validators.rb +37 -36
- data/lib/introspective_grape/version.rb +5 -5
- data/lib/introspective_grape.rb +1 -0
- data/spec/dummy/Gemfile +24 -23
- data/spec/dummy/app/api/{api_helpers.rb → authentication_helper.rb} +38 -38
- data/spec/dummy/app/api/dummy/chat_api.rb +1 -1
- data/spec/dummy/app/api/dummy/company_api.rb +1 -1
- data/spec/dummy/app/api/dummy/location_api.rb +1 -1
- data/spec/dummy/app/api/dummy/project_api.rb +2 -2
- data/spec/dummy/app/api/dummy/role_api.rb +1 -1
- data/spec/dummy/app/api/dummy/sessions.rb +2 -2
- data/spec/dummy/app/api/dummy/user_api.rb +1 -1
- data/spec/dummy/app/api/dummy_api.rb +60 -61
- data/spec/dummy/app/api/error_handlers.rb +6 -6
- data/spec/dummy/app/api/permissions_helper.rb +7 -7
- data/spec/dummy/app/helpers/current.rb +3 -3
- data/spec/dummy/app/models/abstract_adapter.rb +11 -8
- data/spec/dummy/app/models/chat_message.rb +34 -34
- data/spec/dummy/app/models/chat_user.rb +16 -16
- data/spec/dummy/app/models/company.rb +3 -2
- data/spec/dummy/app/models/location.rb +26 -26
- data/spec/dummy/app/models/role.rb +30 -30
- data/spec/dummy/app/models/team.rb +14 -14
- data/spec/dummy/app/models/user/chatter.rb +79 -79
- data/spec/dummy/app/models/user.rb +2 -0
- data/spec/dummy/bin/bundle +3 -3
- data/spec/dummy/bin/rails +4 -4
- data/spec/dummy/bin/setup +36 -36
- data/spec/dummy/bin/update +31 -31
- data/spec/dummy/bin/yarn +11 -11
- data/spec/dummy/config/application.rb +30 -30
- data/spec/dummy/config/boot.rb +3 -3
- data/spec/dummy/config/environment.rb +5 -5
- data/spec/dummy/config/environments/development.rb +54 -54
- data/spec/dummy/config/environments/production.rb +81 -81
- data/spec/dummy/config/environments/test.rb +47 -47
- data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -8
- data/spec/dummy/config/initializers/assets.rb +14 -14
- data/spec/dummy/config/initializers/content_security_policy.rb +25 -25
- data/spec/dummy/config/initializers/cookies_serializer.rb +5 -5
- data/spec/dummy/config/initializers/new_framework_defaults_5_2.rb +38 -38
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -14
- data/spec/dummy/config/locales/en.yml +33 -33
- data/spec/dummy/config/routes.rb +1 -1
- data/spec/dummy/config/storage.yml +34 -34
- data/spec/models/image_spec.rb +10 -10
- data/spec/rails_helper.rb +1 -2
- data/spec/requests/chat_api_spec.rb +1 -1
- data/spec/requests/company_api_spec.rb +1 -1
- data/spec/requests/location_api_spec.rb +1 -1
- data/spec/requests/project_api_spec.rb +185 -185
- data/spec/requests/role_api_spec.rb +1 -1
- data/spec/requests/user_api_spec.rb +221 -221
- data/spec/support/request_helpers.rb +22 -22
- metadata +9 -192
- data/spec/dummy/.ruby-version +0 -1
- data/spec/dummy/config/initializers/inflections.rb +0 -16
@@ -11,7 +11,7 @@ if IntrospectiveGrape.config.camelize_parameters
|
|
11
11
|
parsed_params.each do |param|
|
12
12
|
param[:name] = param[:name]
|
13
13
|
.camelize(:lower)
|
14
|
-
.gsub(
|
14
|
+
.gsub('Destroy', '_destroy')
|
15
15
|
end
|
16
16
|
super(params, path, method, _options = {})
|
17
17
|
end
|
@@ -34,8 +34,8 @@ if IntrospectiveGrape.config.camelize_parameters
|
|
34
34
|
else
|
35
35
|
module CallWithCamelized
|
36
36
|
def call(*args)
|
37
|
-
param = super
|
38
|
-
param[:name] = param[:name].camelize(:lower).gsub(
|
37
|
+
param = super
|
38
|
+
param[:name] = param[:name].camelize(:lower).gsub('Destroy', '_destroy')
|
39
39
|
param
|
40
40
|
end
|
41
41
|
end
|
@@ -1,25 +1,25 @@
|
|
1
|
-
module IntrospectiveGrape
|
2
|
-
module CreateHelpers
|
3
|
-
def add_new_records_to_root_record(dsl, routes, params, model)
|
4
|
-
dsl.send(:authorize, model, :create?)
|
5
|
-
ActiveRecord::Base.transaction do
|
6
|
-
old = find_leaves(routes, model, params)
|
7
|
-
model.update( dsl.send(:safe_params, params).permit(whitelist) )
|
8
|
-
new = find_leaves(routes, model, params)
|
9
|
-
old.respond_to?(:size) ? new - old : new
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def create_new_record(dsl, routes, params)
|
14
|
-
model = routes.first.model.new( dsl.send(:safe_params, params).permit(whitelist) )
|
15
|
-
dsl.send(:authorize, model, :create?)
|
16
|
-
model.save!
|
17
|
-
|
18
|
-
# reload the model with eager loading
|
19
|
-
default_includes = routes.first.klass.default_includes(routes.first.model)
|
20
|
-
model = model.class.includes(default_includes).find(model.id) if model.persisted?
|
21
|
-
|
22
|
-
find_leaves(routes, model, params)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
1
|
+
module IntrospectiveGrape
|
2
|
+
module CreateHelpers
|
3
|
+
def add_new_records_to_root_record(dsl, routes, params, model)
|
4
|
+
dsl.send(:authorize, model, :create?)
|
5
|
+
ActiveRecord::Base.transaction do
|
6
|
+
old = find_leaves(routes, model, params)
|
7
|
+
model.update( dsl.send(:safe_params, params).permit(whitelist) )
|
8
|
+
new = find_leaves(routes, model, params)
|
9
|
+
old.respond_to?(:size) ? new - old : new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_new_record(dsl, routes, params)
|
14
|
+
model = routes.first.model.new( dsl.send(:safe_params, params).permit(whitelist) )
|
15
|
+
dsl.send(:authorize, model, :create?)
|
16
|
+
model.save!
|
17
|
+
|
18
|
+
# reload the model with eager loading
|
19
|
+
default_includes = routes.first.klass.default_includes(routes.first.model)
|
20
|
+
model = model.class.includes(default_includes).find(model.id) if model.persisted?
|
21
|
+
|
22
|
+
find_leaves(routes, model, params)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -62,7 +62,7 @@ module IntrospectiveGrape
|
|
62
62
|
if timestamp_filter(klass, model, field)
|
63
63
|
dsl.optional field, type: klass.param_type(model, field), description: "Constrain #{field} by #{humanize_date_range(field)} date."
|
64
64
|
elsif identifier_filter?(model, field)
|
65
|
-
dsl.optional field, type:
|
65
|
+
dsl.optional field, type: [String], coerce_with: ->(val) { val.split(',') }, description: 'Filter by a comma separated list of unique identifiers.'
|
66
66
|
else
|
67
67
|
dsl.optional field, type: klass.param_type(model, field), description: "Filter on #{field} by value."
|
68
68
|
end
|
@@ -82,7 +82,9 @@ module IntrospectiveGrape
|
|
82
82
|
|
83
83
|
def filter_doc
|
84
84
|
<<-STR
|
85
|
-
|
85
|
+
JSON of conditions for query.
|
86
|
+
|
87
|
+
If you're familiar with ActiveRecord's query conventions you can build more complex filters, i.e. against included child associations, e.g.: {"<association_name>_<parent>":{"field":"value"}}
|
86
88
|
STR
|
87
89
|
end
|
88
90
|
|
@@ -106,7 +108,7 @@ module IntrospectiveGrape
|
|
106
108
|
records = apply_simple_filter(klass, model, params, records, field)
|
107
109
|
end
|
108
110
|
|
109
|
-
klass.custom_filters.
|
111
|
+
klass.custom_filters.each_key do |filter|
|
110
112
|
records = records.send(filter, params[filter])
|
111
113
|
end
|
112
114
|
|
@@ -1,56 +1,56 @@
|
|
1
|
-
module IntrospectiveGrape
|
2
|
-
module Traversal
|
3
|
-
# For deeply nested endpoints we want to present the record being affected, these
|
4
|
-
# methods traverse down from the parent instance to the child model associations
|
5
|
-
# of the deeply nested route.
|
6
|
-
|
7
|
-
def find_leaves(routes, record, params)
|
8
|
-
# Traverse down our route and find the leaf's siblings from its parent, e.g.
|
9
|
-
# project/#/teams/#/team_users ~> project.find.teams.find.team_users
|
10
|
-
# (the traversal of the intermediate nodes occurs in find_leaf())
|
11
|
-
return record if routes.size < 2 # the leaf is the root
|
12
|
-
|
13
|
-
record = find_leaf(routes, record, params) || return
|
14
|
-
|
15
|
-
assoc = routes.last
|
16
|
-
if assoc.many?
|
17
|
-
leaves = record.send( assoc.reflection.name ).includes( default_includes(assoc.model) )
|
18
|
-
verify_records_found(leaves, routes)
|
19
|
-
leaves
|
20
|
-
else
|
21
|
-
# has_one associations don't return a CollectionProxy and so don't support
|
22
|
-
# eager loading.
|
23
|
-
record.send( assoc.reflection.name )
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def verify_records_found(leaves, routes)
|
28
|
-
return if (leaves.map(&:class) - [routes.last.model]).empty?
|
29
|
-
|
30
|
-
raise ActiveRecord::RecordNotFound.new("Records contain the wrong models, they should all be #{routes.last.model.name}, found #{records.map(&:class).map(&:name).join(',')}")
|
31
|
-
end
|
32
|
-
|
33
|
-
def find_leaf(routes, record, params)
|
34
|
-
return record unless routes.size > 1
|
35
|
-
|
36
|
-
# For deeply nested routes we need to search from the root of the API to the leaf
|
37
|
-
# of its nested associations in order to guarantee the validity of the relationship,
|
38
|
-
# the authorization on the parent model, and the sanity of passed parameters.
|
39
|
-
routes[1..].each do |r|
|
40
|
-
if record && params[r.key]
|
41
|
-
ref = r.reflection
|
42
|
-
record = record.send(ref.name).where( id: params[r.key] ).first if ref
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
verify_record_found(routes, params, record)
|
47
|
-
record
|
48
|
-
end
|
49
|
-
|
50
|
-
def verify_record_found(routes, params, record)
|
51
|
-
return unless params[routes.last.key] && record.class != routes.last.model
|
52
|
-
|
53
|
-
raise ActiveRecord::RecordNotFound.new("No #{routes.last.model.name} with ID '#{params[routes.last.key]}'")
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
1
|
+
module IntrospectiveGrape
|
2
|
+
module Traversal
|
3
|
+
# For deeply nested endpoints we want to present the record being affected, these
|
4
|
+
# methods traverse down from the parent instance to the child model associations
|
5
|
+
# of the deeply nested route.
|
6
|
+
|
7
|
+
def find_leaves(routes, record, params)
|
8
|
+
# Traverse down our route and find the leaf's siblings from its parent, e.g.
|
9
|
+
# project/#/teams/#/team_users ~> project.find.teams.find.team_users
|
10
|
+
# (the traversal of the intermediate nodes occurs in find_leaf())
|
11
|
+
return record if routes.size < 2 # the leaf is the root
|
12
|
+
|
13
|
+
record = find_leaf(routes, record, params) || return
|
14
|
+
|
15
|
+
assoc = routes.last
|
16
|
+
if assoc.many?
|
17
|
+
leaves = record.send( assoc.reflection.name ).includes( default_includes(assoc.model) )
|
18
|
+
verify_records_found(leaves, routes)
|
19
|
+
leaves
|
20
|
+
else
|
21
|
+
# has_one associations don't return a CollectionProxy and so don't support
|
22
|
+
# eager loading.
|
23
|
+
record.send( assoc.reflection.name )
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def verify_records_found(leaves, routes)
|
28
|
+
return if (leaves.map(&:class) - [routes.last.model]).empty?
|
29
|
+
|
30
|
+
raise ActiveRecord::RecordNotFound.new("Records contain the wrong models, they should all be #{routes.last.model.name}, found #{records.map(&:class).map(&:name).join(',')}")
|
31
|
+
end
|
32
|
+
|
33
|
+
def find_leaf(routes, record, params)
|
34
|
+
return record unless routes.size > 1
|
35
|
+
|
36
|
+
# For deeply nested routes we need to search from the root of the API to the leaf
|
37
|
+
# of its nested associations in order to guarantee the validity of the relationship,
|
38
|
+
# the authorization on the parent model, and the sanity of passed parameters.
|
39
|
+
routes[1..].each do |r|
|
40
|
+
if record && params[r.key]
|
41
|
+
ref = r.reflection
|
42
|
+
record = record.send(ref.name).where( id: params[r.key] ).first if ref
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
verify_record_found(routes, params, record)
|
47
|
+
record
|
48
|
+
end
|
49
|
+
|
50
|
+
def verify_record_found(routes, params, record)
|
51
|
+
return unless params[routes.last.key] && record.class != routes.last.model
|
52
|
+
|
53
|
+
raise ActiveRecord::RecordNotFound.new("No #{routes.last.model.name} with ID '#{params[routes.last.key]}'")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -1,36 +1,37 @@
|
|
1
|
-
require 'grape/validations'
|
2
|
-
module Grape
|
3
|
-
module Validators
|
4
|
-
# Validations::Base becomes Validators::Base somewhere between 1.6.0 and 1.6.2
|
5
|
-
validation_class = defined?(Grape::Validations::Base) ? Grape::Validations::Base : Grape::Validations::
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
1
|
+
require 'grape/validations'
|
2
|
+
module Grape
|
3
|
+
module Validators
|
4
|
+
# Validations::Base becomes Validators::Base somewhere between 1.6.0 and 1.6.2
|
5
|
+
validation_class = defined?(Grape::Validations::Validators::Base) ? Grape::Validations::Validators::Base : Grape::Validations::Base
|
6
|
+
|
7
|
+
class Json < validation_class
|
8
|
+
def validate_param!(field, params)
|
9
|
+
begin
|
10
|
+
JSON.parse( params[field] )
|
11
|
+
rescue StandardError
|
12
|
+
raise Grape::Exceptions::Validation.new params: [@scope.full_name(field)], message: 'must be valid JSON!'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class JsonArray < validation_class
|
18
|
+
def validate_param!(field, params)
|
19
|
+
begin
|
20
|
+
raise unless JSON.parse( params[field] ).is_a? Array
|
21
|
+
rescue StandardError
|
22
|
+
raise Grape::Exceptions::Validation.new params: [@scope.full_name(field)], message: 'must be a valid JSON array!'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class JsonHash < validation_class
|
28
|
+
def validate_param!(field, params)
|
29
|
+
begin
|
30
|
+
raise unless JSON.parse( params[field] ).is_a? Hash
|
31
|
+
rescue StandardError
|
32
|
+
raise Grape::Exceptions::Validation.new params: [@scope.full_name(field)], message: 'must be a valid JSON hash!'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module IntrospectiveGrape
|
4
|
-
VERSION = '0.
|
5
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IntrospectiveGrape
|
4
|
+
VERSION = '0.7.0'
|
5
|
+
end
|
data/lib/introspective_grape.rb
CHANGED
@@ -9,6 +9,7 @@ module IntrospectiveGrape
|
|
9
9
|
autoload :Helpers, 'introspective_grape/helpers'
|
10
10
|
autoload :SnakeParams, 'introspective_grape/snake_params'
|
11
11
|
autoload :Traversal, 'introspective_grape/traversal'
|
12
|
+
autoload :Route, 'introspective_grape/route'
|
12
13
|
|
13
14
|
module Formatter
|
14
15
|
autoload :CamelJson, 'introspective_grape/formatter/camel_json'
|
data/spec/dummy/Gemfile
CHANGED
@@ -1,23 +1,24 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
gem 'rails' #, '5.2.6.2'
|
3
|
-
|
4
|
-
gem 'byebug'
|
5
|
-
gem 'listen'
|
6
|
-
gem 'camel_snake_keys'
|
7
|
-
|
8
|
-
gem 'devise'
|
9
|
-
gem 'delayed_paperclip'
|
10
|
-
gem 'kt-paperclip'
|
11
|
-
|
12
|
-
gem 'grape'
|
13
|
-
gem 'grape-entity'
|
14
|
-
gem 'grape-kaminari'
|
15
|
-
gem 'grape-swagger'
|
16
|
-
gem 'grape-swagger-entity'
|
17
|
-
gem 'introspective_grape', path: '~/Dropbox/contrib/introspective_grape'
|
18
|
-
|
19
|
-
gem 'paperclip'
|
20
|
-
gem 'pundit'
|
21
|
-
|
22
|
-
gem 'rack-cors'
|
23
|
-
gem 'sqlite3'
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
gem 'rails' #, '5.2.6.2'
|
3
|
+
|
4
|
+
gem 'byebug'
|
5
|
+
gem 'listen'
|
6
|
+
gem 'camel_snake_keys'
|
7
|
+
|
8
|
+
gem 'devise'
|
9
|
+
gem 'delayed_paperclip'
|
10
|
+
gem 'kt-paperclip'
|
11
|
+
|
12
|
+
gem 'grape'
|
13
|
+
gem 'grape-entity'
|
14
|
+
gem 'grape-kaminari'
|
15
|
+
gem 'grape-swagger'
|
16
|
+
gem 'grape-swagger-entity'
|
17
|
+
gem 'introspective_grape', path: '~/Dropbox/contrib/introspective_grape'
|
18
|
+
|
19
|
+
gem 'paperclip'
|
20
|
+
gem 'pundit'
|
21
|
+
|
22
|
+
gem 'rack-cors'
|
23
|
+
gem 'sqlite3'
|
24
|
+
gem 'validates_by_schema'
|
@@ -1,38 +1,38 @@
|
|
1
|
-
module
|
2
|
-
def current_user
|
3
|
-
params[:api_key].present? && @user = User.find_by_authentication_token(params[:api_key])
|
4
|
-
# for testing in situ
|
5
|
-
@user = User.find_or_create_by(email: 'test@test.com', superuser: true, authentication_token: '1234567890', first_name: "First", last_name: "Last")
|
6
|
-
Current.user = @user
|
7
|
-
end
|
8
|
-
|
9
|
-
def authenticate!
|
10
|
-
unauthenticated! unless login_request? || current_user
|
11
|
-
end
|
12
|
-
|
13
|
-
def login_request?
|
14
|
-
self.method_name.start_with?('POST') && self.namespace == '/sessions'
|
15
|
-
end
|
16
|
-
|
17
|
-
# returns an 'unauthenticated' response
|
18
|
-
def unauthenticated!(error_type = nil)
|
19
|
-
respond_error!('unauthenticated', error_type, 401)
|
20
|
-
end
|
21
|
-
|
22
|
-
# returns a error response with given type, message_key and status
|
23
|
-
def respond_error!(type, message_key, status = 500, other = {})
|
24
|
-
e = {
|
25
|
-
type: type,
|
26
|
-
status: status
|
27
|
-
}
|
28
|
-
e['message_key'] = message_key if message_key
|
29
|
-
e.merge!(other)
|
30
|
-
error!({ error: e }, status)
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def safe_params(params)
|
36
|
-
ActionController::Parameters.new(params)
|
37
|
-
end
|
38
|
-
end
|
1
|
+
module AuthenticationHelper
|
2
|
+
def current_user
|
3
|
+
params[:api_key].present? && @user = User.find_by_authentication_token(params[:api_key])
|
4
|
+
# for testing in situ
|
5
|
+
@user = User.find_or_create_by(email: 'test@test.com', superuser: true, authentication_token: '1234567890', first_name: "First", last_name: "Last")
|
6
|
+
Current.user = @user
|
7
|
+
end
|
8
|
+
|
9
|
+
def authenticate!
|
10
|
+
unauthenticated! unless login_request? || current_user
|
11
|
+
end
|
12
|
+
|
13
|
+
def login_request?
|
14
|
+
self.method_name.start_with?('POST') && self.namespace == '/sessions'
|
15
|
+
end
|
16
|
+
|
17
|
+
# returns an 'unauthenticated' response
|
18
|
+
def unauthenticated!(error_type = nil)
|
19
|
+
respond_error!('unauthenticated', error_type, 401)
|
20
|
+
end
|
21
|
+
|
22
|
+
# returns a error response with given type, message_key and status
|
23
|
+
def respond_error!(type, message_key, status = 500, other = {})
|
24
|
+
e = {
|
25
|
+
type: type,
|
26
|
+
status: status
|
27
|
+
}
|
28
|
+
e['message_key'] = message_key if message_key
|
29
|
+
e.merge!(other)
|
30
|
+
error!({ error: e }, status)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def safe_params(params)
|
36
|
+
ActionController::Parameters.new(params)
|
37
|
+
end
|
38
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class Dummy::
|
1
|
+
class Dummy::ProjectApi < IntrospectiveGrape::API
|
2
2
|
include Grape::Kaminari
|
3
3
|
|
4
4
|
default_includes Project, :owner, :admins, :user_project_jobs, project_jobs: [:job], teams: [:team_users]
|
@@ -43,7 +43,7 @@ class Dummy::ProjectAPI < IntrospectiveGrape::API
|
|
43
43
|
|
44
44
|
class ProjectEntity < Grape::Entity
|
45
45
|
expose :id, :name, :created_at, :updated_at
|
46
|
-
expose :owner, using: Dummy::
|
46
|
+
expose :owner, using: Dummy::CompanyApi::CompanyEntity
|
47
47
|
expose :admins, using: AdminEntity
|
48
48
|
expose :project_jobs, as: :jobs, using: JobEntity
|
49
49
|
expose :user_project_jobs, as: :user_jobs, using: UserJobEntity
|
@@ -16,7 +16,7 @@ class Dummy::Sessions < Grape::API #::Instance
|
|
16
16
|
if user && user.valid_password?(params[:password]) && user.valid_for_authentication?
|
17
17
|
|
18
18
|
# commented out for now, User model is not yet confirmable
|
19
|
-
#unauthenticated!
|
19
|
+
#unauthenticated! DummyApi::USER_NOT_CONFIRMED unless user.confirmed?
|
20
20
|
|
21
21
|
token = nil
|
22
22
|
if params[:token]
|
@@ -28,7 +28,7 @@ class Dummy::Sessions < Grape::API #::Instance
|
|
28
28
|
env['warden'].set_user(user, scope: :user)
|
29
29
|
present user, with: Dummy::Entities::User, token: token
|
30
30
|
else
|
31
|
-
unauthenticated!
|
31
|
+
unauthenticated! DummyApi::BAD_LOGIN
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
@@ -1,61 +1,60 @@
|
|
1
|
-
require 'byebug'
|
2
|
-
require 'grape-kaminari'
|
3
|
-
class
|
4
|
-
include Grape::Kaminari
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
helpers
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
header "
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
api =
|
41
|
-
api
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
1
|
+
require 'byebug'
|
2
|
+
require 'grape-kaminari'
|
3
|
+
class DummyApi < Grape::API #::Instance
|
4
|
+
include Grape::Kaminari
|
5
|
+
include ErrorHandlers
|
6
|
+
|
7
|
+
version 'v1', using: :path
|
8
|
+
format :json
|
9
|
+
formatter :json, IntrospectiveGrape::Formatter::CamelJson
|
10
|
+
default_format :json
|
11
|
+
|
12
|
+
helpers PermissionsHelper
|
13
|
+
helpers AuthenticationHelper
|
14
|
+
|
15
|
+
USER_NOT_CONFIRMED = 'user_not_confirmed'.freeze
|
16
|
+
BAD_LOGIN = 'bad_login'.freeze
|
17
|
+
|
18
|
+
before do
|
19
|
+
# sets server date in response header. This can be used on the client side
|
20
|
+
header "X-Server-Date", Time.now.to_i.to_s
|
21
|
+
header "Expires", 1.year.ago.httpdate
|
22
|
+
end
|
23
|
+
|
24
|
+
before_validation do
|
25
|
+
Rails.logger.info "With params: #{params.to_hash.inspect}"
|
26
|
+
end
|
27
|
+
|
28
|
+
after do
|
29
|
+
unless self.options[:path].first =~ /swagger/
|
30
|
+
verify_authorized # Ensure that all endpoints are authorized by a policy class
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Load the in-memory database for the test app
|
35
|
+
# load "#{Rails.root}/db/schema.rb"
|
36
|
+
|
37
|
+
# Mount every api endpoint under app/api/dummy/.
|
38
|
+
Dir.glob(Rails.root+"app"+"api"+'dummy'+'*.rb').each do |f|
|
39
|
+
api = "Dummy::#{File.basename(f, '.rb').camelize}"
|
40
|
+
api = api.constantize
|
41
|
+
mount api if api.respond_to? :endpoints
|
42
|
+
end
|
43
|
+
|
44
|
+
# configure grape-swagger to auto-generate swagger docs
|
45
|
+
add_swagger_documentation({
|
46
|
+
base_path: "/api",
|
47
|
+
doc_version: 'v1',
|
48
|
+
hide_documentation_path: true,
|
49
|
+
format: :json,
|
50
|
+
hide_format: true,
|
51
|
+
security_definitions: {
|
52
|
+
api_key: {
|
53
|
+
type: "apiKey",
|
54
|
+
name: "api_key",
|
55
|
+
in: "header"
|
56
|
+
}
|
57
|
+
}
|
58
|
+
})
|
59
|
+
|
60
|
+
end
|