openstax_api 3.0.1 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/representers/openstax/api/v1/abstract_search_representer.rb +9 -1
- data/lib/openstax/api/doorkeeper_application_includes.rb +4 -0
- data/lib/openstax/api/engine.rb +1 -0
- data/lib/openstax/api/representable_schema_printer.rb +8 -5
- data/lib/openstax/api/roar.rb +61 -28
- data/lib/openstax/api/routing_mapper_includes.rb +2 -1
- data/lib/openstax/api/version.rb +1 -1
- data/spec/dummy/app/routines/search_users.rb +0 -1
- data/spec/dummy/config/initializers/doorkeeper.rb +1 -1
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +5133 -0
- data/spec/lib/openstax/api/roar_spec.rb +3 -2
- data/spec/lib/openstax/api/routing_mapper_includes_spec.rb +1 -2
- data/spec/representers/openstax/api/v1/abstract_search_representer_spec.rb +15 -9
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3b74dc93f1361a2e644ad8f4977ae5daa9d27c0
|
4
|
+
data.tar.gz: 2258ff732a6fc77dc869a7826812f2dcbdadb9f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05e1dd62fe6cede4ce4778ca1ad107210d3337c726b6f669f38f36b48b10c23e3472e90d88920793b2844fa6cc3f32b836ca058ea1badb000ab758aead0fbc5b
|
7
|
+
data.tar.gz: 9815ae41155f318cfdf003d8e8daaa3d0bae2c0eaf545beaa5308fbef1dab459b88e1dcb76774e0c2430d5db5f73b7bcbc557cb5bfc96390e087896eed38c12e
|
@@ -31,7 +31,15 @@ module OpenStax
|
|
31
31
|
}
|
32
32
|
|
33
33
|
def total_count
|
34
|
-
represented[:total_count]
|
34
|
+
return represented[:total_count] if represented[:total_count]
|
35
|
+
case represented[:items]
|
36
|
+
when ActiveRecord::Relation
|
37
|
+
represented[:items].limit(nil).offset(nil).count
|
38
|
+
when Array
|
39
|
+
represented[:items].count
|
40
|
+
else
|
41
|
+
1
|
42
|
+
end
|
35
43
|
end
|
36
44
|
|
37
45
|
end
|
data/lib/openstax/api/engine.rb
CHANGED
@@ -27,7 +27,7 @@ module OpenStax
|
|
27
27
|
|
28
28
|
# Attempts to extract the given representer's name
|
29
29
|
def self.representer_name(representer)
|
30
|
-
name = representer.name
|
30
|
+
name = representer.try :name
|
31
31
|
return nil if name.nil?
|
32
32
|
name.chomp('Representer').demodulize.camelize(:lower)
|
33
33
|
end
|
@@ -85,10 +85,13 @@ module OpenStax
|
|
85
85
|
|
86
86
|
# Get the nested representers
|
87
87
|
# Evaluate syntax is evaluate(context, instance or class, *args)
|
88
|
-
#
|
89
|
-
# By convention,
|
90
|
-
#
|
91
|
-
|
88
|
+
# If we have no instance or class (since we have no fragment), we pass Object
|
89
|
+
# By convention, our callables should return an array of all possible
|
90
|
+
# representers when we pass the :all_sub_representers => true option
|
91
|
+
instance = attr[:instance].evaluate(representer, {}) rescue nil
|
92
|
+
klass = attr[:class].evaluate(representer, {}) rescue Object
|
93
|
+
decorators = [attr[:extend].evaluate(representer, instance || klass,
|
94
|
+
:all_sub_representers => true)].flatten.compact rescue []
|
92
95
|
|
93
96
|
# Count the representers
|
94
97
|
include_oneof = decorators.length > 1
|
data/lib/openstax/api/roar.rb
CHANGED
@@ -2,21 +2,43 @@
|
|
2
2
|
# License version 3 or later. See the COPYRIGHT file for details.
|
3
3
|
|
4
4
|
require 'openstax_utilities'
|
5
|
+
require 'lev'
|
5
6
|
|
6
7
|
module OpenStax
|
7
8
|
module Api
|
8
9
|
|
9
10
|
module Roar
|
10
11
|
|
11
|
-
def standard_search(routine,
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
def standard_search(routine, relation, represent_with, options={})
|
13
|
+
user = current_api_user
|
14
|
+
model_klass = relation.base_class
|
15
|
+
OSU::AccessPolicy.require_action_allowed!(:search, user, model_klass)
|
16
|
+
options = options.merge({
|
17
|
+
search_routine: routine,
|
18
|
+
search_relation: relation,
|
19
|
+
params: params
|
20
|
+
})
|
21
|
+
result = OpenStax::Utilities::KeywordSearchHandler.call(options)
|
22
|
+
return render_api_errors(result.errors) if result.errors.any?
|
23
|
+
outputs = result.outputs
|
24
|
+
outputs[:items].each do |item|
|
25
|
+
OSU::AccessPolicy.require_action_allowed!(:read, user, item)
|
26
|
+
end
|
15
27
|
respond_with outputs, represent_with: represent_with
|
16
28
|
end
|
17
29
|
|
18
|
-
def standard_create(model, represent_with=nil
|
19
|
-
|
30
|
+
def standard_create(model, represent_with=nil)
|
31
|
+
model.class.transaction do
|
32
|
+
consume!(model, represent_with: represent_with)
|
33
|
+
yield model if block_given?
|
34
|
+
OSU::AccessPolicy.require_action_allowed!(:create, current_api_user, model)
|
35
|
+
|
36
|
+
if model.save
|
37
|
+
respond_with model, represent_with: represent_with, status: :created
|
38
|
+
else
|
39
|
+
render_api_errors(model.errors)
|
40
|
+
end
|
41
|
+
end
|
20
42
|
end
|
21
43
|
|
22
44
|
def standard_read(model, represent_with=nil)
|
@@ -25,6 +47,7 @@ module OpenStax
|
|
25
47
|
end
|
26
48
|
|
27
49
|
def standard_update(model, represent_with=nil)
|
50
|
+
# Must be able to update the record before and after the update itself
|
28
51
|
OSU::AccessPolicy.require_action_allowed!(:update, current_api_user, model)
|
29
52
|
|
30
53
|
model.class.transaction do
|
@@ -35,7 +58,7 @@ module OpenStax
|
|
35
58
|
if model.save
|
36
59
|
head :no_content
|
37
60
|
else
|
38
|
-
|
61
|
+
render_api_errors(model.errors)
|
39
62
|
end
|
40
63
|
end
|
41
64
|
end
|
@@ -46,43 +69,53 @@ module OpenStax
|
|
46
69
|
if model.destroy
|
47
70
|
head :no_content
|
48
71
|
else
|
49
|
-
|
72
|
+
render_api_errors(model.errors)
|
50
73
|
end
|
51
74
|
end
|
52
75
|
|
53
76
|
def standard_index(relation, represent_with)
|
54
77
|
model_klass = relation.base_class
|
55
78
|
OSU::AccessPolicy.require_action_allowed!(:index, current_api_user, model_klass)
|
56
|
-
|
79
|
+
relation.each do |item|
|
80
|
+
# Must be able to read each record
|
81
|
+
OSU::AccessPolicy.require_action_allowed!(:read, current_api_user, item)
|
82
|
+
end
|
83
|
+
respond_with(Lev::Outputs.new({items: relation}), {represent_with: represent_with})
|
57
84
|
end
|
58
85
|
|
59
86
|
def standard_sort(*args)
|
60
87
|
raise NotYetImplemented
|
61
88
|
end
|
62
89
|
|
63
|
-
def standard_nested_create(model, container_association
|
64
|
-
container
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
90
|
+
def standard_nested_create(model, container_association,
|
91
|
+
container, represent_with=nil)
|
92
|
+
# Must be able to update the container
|
93
|
+
OSU::AccessPolicy.require_action_allowed!(:update, current_api_user, container)
|
94
|
+
model.send("#{container_association.to_s}=", container)
|
69
95
|
|
70
|
-
|
71
|
-
|
72
|
-
# We do want to consume before checking the permissions so we can know
|
73
|
-
# what we're dealing with, but if user doesn't have permission we don't
|
74
|
-
# want to have changed the DB. Wrap in a transaction to protect ourselves.
|
75
|
-
model.class.transaction do
|
76
|
-
consume!(model, represent_with: represent_with)
|
77
|
-
yield model if block_given?
|
78
|
-
OSU::AccessPolicy.require_action_allowed!(:create, current_api_user, model)
|
96
|
+
standard_create(model, represent_with)
|
97
|
+
end
|
79
98
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
99
|
+
def render_api_errors(errors, status = :unprocessable_entity)
|
100
|
+
hash = {status: Rack::Utils.status_code(status)}
|
101
|
+
case errors
|
102
|
+
when ActiveModel::Errors, Lev::BetterActiveModelErrors
|
103
|
+
hash[:errors] = []
|
104
|
+
errors.each do |attribute, message|
|
105
|
+
hash[:errors] << {code: "#{attribute.to_s}_#{
|
106
|
+
message.to_s.gsub(/[\s-]/, '_').gsub(/[^\w]/, '')
|
107
|
+
}", message: errors.full_message(attribute, message)}
|
108
|
+
end
|
109
|
+
when Lev::Errors
|
110
|
+
hash[:errors] = errors.collect do |error|
|
111
|
+
{code: error.code, message: error.message, data: error.data}
|
112
|
+
end
|
113
|
+
else
|
114
|
+
hash[:errors] = [errors].flatten.collect do |error|
|
115
|
+
{code: error.to_s}
|
84
116
|
end
|
85
117
|
end
|
118
|
+
render json: hash, status: status
|
86
119
|
end
|
87
120
|
|
88
121
|
end
|
@@ -11,7 +11,8 @@ module OpenStax
|
|
11
11
|
default: options.delete(:default))
|
12
12
|
|
13
13
|
namespace api_namespace, defaults: {format: 'json'}.merge(options) do
|
14
|
-
scope(
|
14
|
+
scope(except: [:new, :edit],
|
15
|
+
module: version,
|
15
16
|
constraints: constraints) do
|
16
17
|
get '/', to: '/apipie/apipies#index', defaults: {format: 'html',
|
17
18
|
version: version.to_s}
|
data/lib/openstax/api/version.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# Dummy routine for testing the abstract search representer
|
2
2
|
|
3
3
|
class SearchUsers < OpenStax::Utilities::AbstractKeywordSearchRoutine
|
4
|
-
self.initial_relation = User.unscoped
|
5
4
|
self.search_proc = lambda { |with|
|
6
5
|
with.keyword :username do |names|
|
7
6
|
snames = to_string_array(names, append_wildcard: true)
|
data/spec/dummy/db/test.sqlite3
CHANGED
Binary file
|