openstax_api 3.0.1 → 3.1.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/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
|