croods 0.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +19 -0
- data/lib/croods.rb +58 -0
- data/lib/croods/action.rb +17 -0
- data/lib/croods/api.rb +26 -0
- data/lib/croods/api/initial_schema.json +52 -0
- data/lib/croods/attribute.rb +15 -0
- data/lib/croods/controller.rb +28 -0
- data/lib/croods/controller/actions.rb +71 -0
- data/lib/croods/controller/already_taken.rb +27 -0
- data/lib/croods/controller/authentication.rb +22 -0
- data/lib/croods/controller/authorization.rb +31 -0
- data/lib/croods/controller/collection.rb +15 -0
- data/lib/croods/controller/member.rb +45 -0
- data/lib/croods/controller/model.rb +17 -0
- data/lib/croods/controller/multi_tenancy.rb +54 -0
- data/lib/croods/controller/not_found.rb +22 -0
- data/lib/croods/controller/record_invalid.rb +22 -0
- data/lib/croods/controller/resource.rb +30 -0
- data/lib/croods/middleware.rb +44 -0
- data/lib/croods/middleware/base.rb +20 -0
- data/lib/croods/middleware/request_validation.rb +10 -0
- data/lib/croods/middleware/response_validation.rb +10 -0
- data/lib/croods/model.rb +41 -0
- data/lib/croods/policy.rb +118 -0
- data/lib/croods/policy/scope.rb +131 -0
- data/lib/croods/railtie.rb +6 -0
- data/lib/croods/resource.rb +39 -0
- data/lib/croods/resource/actions.rb +51 -0
- data/lib/croods/resource/attributes.rb +53 -0
- data/lib/croods/resource/attributes/base.rb +30 -0
- data/lib/croods/resource/attributes/request.rb +29 -0
- data/lib/croods/resource/attributes/response.rb +13 -0
- data/lib/croods/resource/authentication.rb +46 -0
- data/lib/croods/resource/authorization.rb +47 -0
- data/lib/croods/resource/controller.rb +50 -0
- data/lib/croods/resource/filters.rb +32 -0
- data/lib/croods/resource/identifier.rb +13 -0
- data/lib/croods/resource/json_schema.rb +32 -0
- data/lib/croods/resource/json_schema/definition.rb +34 -0
- data/lib/croods/resource/json_schema/definitions.rb +31 -0
- data/lib/croods/resource/json_schema/initial_schema.json +8 -0
- data/lib/croods/resource/json_schema/links.rb +40 -0
- data/lib/croods/resource/json_schema/links/collection.rb +70 -0
- data/lib/croods/resource/json_schema/links/create.rb +41 -0
- data/lib/croods/resource/json_schema/links/destroy.rb +40 -0
- data/lib/croods/resource/json_schema/links/index.rb +17 -0
- data/lib/croods/resource/json_schema/links/member.rb +40 -0
- data/lib/croods/resource/json_schema/links/show.rb +40 -0
- data/lib/croods/resource/json_schema/links/update.rb +40 -0
- data/lib/croods/resource/json_schema/properties.rb +32 -0
- data/lib/croods/resource/json_schema/required.rb +34 -0
- data/lib/croods/resource/model.rb +35 -0
- data/lib/croods/resource/names.rb +23 -0
- data/lib/croods/resource/paths.rb +16 -0
- data/lib/croods/resource/policy.rb +51 -0
- data/lib/croods/resource/services.rb +18 -0
- data/lib/croods/resource/sorting.rb +13 -0
- data/lib/croods/routes.rb +46 -0
- data/lib/croods/service.rb +28 -0
- data/lib/croods/version.rb +5 -0
- data/lib/tasks/croods_tasks.rake +4 -0
- metadata +316 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
module Resource
|
5
|
+
module Controller
|
6
|
+
def extend_controller(&block)
|
7
|
+
return unless block
|
8
|
+
|
9
|
+
controller_blocks << block
|
10
|
+
end
|
11
|
+
|
12
|
+
def controller_blocks
|
13
|
+
@controller_blocks ||= []
|
14
|
+
end
|
15
|
+
|
16
|
+
def controller_name
|
17
|
+
"#{namespace}Controller"
|
18
|
+
end
|
19
|
+
|
20
|
+
def controller
|
21
|
+
controller_name.constantize
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_controller!
|
25
|
+
Object.const_set(controller_name, Class.new(ApplicationController))
|
26
|
+
|
27
|
+
controller_blocks.each do |block|
|
28
|
+
controller.instance_eval(&block)
|
29
|
+
end
|
30
|
+
|
31
|
+
create_actions!
|
32
|
+
create_additional_actions!
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_actions!
|
36
|
+
actions.each do |action|
|
37
|
+
controller.define_method(
|
38
|
+
action.name, Croods::Controller::Actions.send(action.name)
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_additional_actions!
|
44
|
+
additional_actions.each do |action|
|
45
|
+
controller.define_method(action.name, &action.block)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
module Resource
|
5
|
+
module Filters
|
6
|
+
def filter_by(name, optional: nil)
|
7
|
+
filters << Croods::Attribute.new(
|
8
|
+
name, :string, null: optional
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
def filters
|
13
|
+
@filters ||= []
|
14
|
+
end
|
15
|
+
|
16
|
+
def apply_filters(scope, params)
|
17
|
+
filters.each do |attribute|
|
18
|
+
unless model.has_attribute?(attribute.name)
|
19
|
+
attribute.name = "#{attribute.name}_id"
|
20
|
+
end
|
21
|
+
|
22
|
+
value = params[attribute.name]
|
23
|
+
next unless value
|
24
|
+
|
25
|
+
scope = scope.where(attribute.name => value)
|
26
|
+
end
|
27
|
+
|
28
|
+
scope
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'json_schema/definition'
|
4
|
+
require_relative 'json_schema/definitions'
|
5
|
+
require_relative 'json_schema/properties'
|
6
|
+
require_relative 'json_schema/required'
|
7
|
+
require_relative 'json_schema/links'
|
8
|
+
|
9
|
+
module Croods
|
10
|
+
module Resource
|
11
|
+
module JsonSchema
|
12
|
+
def json_schema
|
13
|
+
return @json_schema if @json_schema
|
14
|
+
|
15
|
+
path = File.expand_path('json_schema/initial_schema.json', __dir__)
|
16
|
+
@json_schema = JSON.parse(File.read(path))
|
17
|
+
@json_schema['definitions'] = Definitions.schema(self)
|
18
|
+
@json_schema['properties'] = Properties.schema(self)
|
19
|
+
@json_schema['required'] = Required.schema(self)
|
20
|
+
@json_schema['links'] = Links.schema(self)
|
21
|
+
@json_schema
|
22
|
+
end
|
23
|
+
|
24
|
+
def ref(attribute = nil)
|
25
|
+
{
|
26
|
+
'$ref': "#/definitions/#{resource_name}" +
|
27
|
+
(attribute ? "/definitions/#{attribute}" : '')
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
module Resource
|
5
|
+
module JsonSchema
|
6
|
+
module Definition
|
7
|
+
TYPES = { datetime: 'string', text: 'string', json: 'object' }.freeze
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def schema(attribute)
|
11
|
+
{ type: types(attribute) }.merge(format(attribute))
|
12
|
+
end
|
13
|
+
|
14
|
+
def format(attribute)
|
15
|
+
return {} unless attribute.type == :datetime
|
16
|
+
|
17
|
+
{ format: 'date-time' }
|
18
|
+
end
|
19
|
+
|
20
|
+
def types(attribute)
|
21
|
+
types = []
|
22
|
+
types << type(attribute.type)
|
23
|
+
types << 'null' if attribute.null
|
24
|
+
types
|
25
|
+
end
|
26
|
+
|
27
|
+
def type(type)
|
28
|
+
TYPES[type] || type.to_s
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
module Resource
|
5
|
+
module JsonSchema
|
6
|
+
module Definitions
|
7
|
+
TYPES = { datetime: 'string', text: 'string', json: 'object' }.freeze
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def schema(resource)
|
11
|
+
attributes(resource).merge(identity: identity(resource))
|
12
|
+
end
|
13
|
+
|
14
|
+
def attributes(resource)
|
15
|
+
attributes = {}
|
16
|
+
|
17
|
+
resource.definitions.each_value do |attribute|
|
18
|
+
attributes[attribute.name] = Definition.schema(attribute)
|
19
|
+
end
|
20
|
+
|
21
|
+
attributes
|
22
|
+
end
|
23
|
+
|
24
|
+
def identity(resource)
|
25
|
+
resource.ref(resource.identifier)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'links/collection'
|
4
|
+
require_relative 'links/member'
|
5
|
+
require_relative 'links/index'
|
6
|
+
require_relative 'links/create'
|
7
|
+
require_relative 'links/update'
|
8
|
+
require_relative 'links/destroy'
|
9
|
+
require_relative 'links/show'
|
10
|
+
|
11
|
+
module Croods
|
12
|
+
module Resource
|
13
|
+
module JsonSchema
|
14
|
+
module Links
|
15
|
+
class << self
|
16
|
+
def schema(resource)
|
17
|
+
additional_actions(resource) + actions(resource)
|
18
|
+
end
|
19
|
+
|
20
|
+
def actions(resource)
|
21
|
+
resource.actions.map do |action|
|
22
|
+
action_module(action.name).link(resource)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def additional_actions(resource)
|
27
|
+
resource.additional_actions.map do |action|
|
28
|
+
action_module(action.on).link(resource, action)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def action_module(name)
|
33
|
+
"Croods::Resource::JsonSchema::Links::#{name.to_s.titleize}"
|
34
|
+
.constantize
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
module Resource
|
5
|
+
module JsonSchema
|
6
|
+
module Links
|
7
|
+
module Collection
|
8
|
+
class << self
|
9
|
+
def link(resource, action = nil)
|
10
|
+
href = resource.collection_path
|
11
|
+
href += "/#{action.name}" if action
|
12
|
+
|
13
|
+
{
|
14
|
+
href: href,
|
15
|
+
method: action&.method&.upcase || 'GET',
|
16
|
+
rel: 'instances',
|
17
|
+
schema: schema(resource),
|
18
|
+
targetSchema: target_schema(resource)
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def filters(resource)
|
23
|
+
filters = {}
|
24
|
+
|
25
|
+
resource.filters.each do |attribute|
|
26
|
+
unless resource.model.has_attribute?(attribute.name)
|
27
|
+
attribute.name = "#{attribute.name}_id"
|
28
|
+
end
|
29
|
+
|
30
|
+
filters[attribute.name] = definition(attribute)
|
31
|
+
end
|
32
|
+
|
33
|
+
filters
|
34
|
+
end
|
35
|
+
|
36
|
+
def definition(attribute)
|
37
|
+
definition = Definition.schema(attribute)
|
38
|
+
|
39
|
+
{
|
40
|
+
anyOf: [{ type: ['array'], items: definition }, definition]
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def required(resource)
|
45
|
+
resource.filters.reject(&:null).map(&:name)
|
46
|
+
end
|
47
|
+
|
48
|
+
def schema(resource)
|
49
|
+
{
|
50
|
+
additionalProperties: false,
|
51
|
+
properties: filters(resource),
|
52
|
+
required: required(resource),
|
53
|
+
type: ['object']
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def target_schema(resource)
|
58
|
+
{
|
59
|
+
anyOf: [
|
60
|
+
{ type: ['array'], items: resource.ref },
|
61
|
+
{ '$ref': '#/definitions/error' }
|
62
|
+
]
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
module Resource
|
5
|
+
module JsonSchema
|
6
|
+
module Links
|
7
|
+
module Create
|
8
|
+
class << self
|
9
|
+
def link(resource)
|
10
|
+
{
|
11
|
+
href: resource.collection_path,
|
12
|
+
method: 'POST',
|
13
|
+
rel: 'new',
|
14
|
+
schema: schema(resource),
|
15
|
+
targetSchema: target_schema(resource)
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def schema(resource)
|
20
|
+
{
|
21
|
+
additionalProperties: false,
|
22
|
+
properties: Properties.schema(resource, request: true),
|
23
|
+
required: Required.schema(resource, request: true),
|
24
|
+
type: ['object']
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def target_schema(resource)
|
29
|
+
{
|
30
|
+
anyOf: [
|
31
|
+
resource.ref,
|
32
|
+
{ '$ref': '#/definitions/error' }
|
33
|
+
]
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
module Resource
|
5
|
+
module JsonSchema
|
6
|
+
module Links
|
7
|
+
module Destroy
|
8
|
+
class << self
|
9
|
+
def link(resource)
|
10
|
+
{
|
11
|
+
href: resource.member_path,
|
12
|
+
method: 'DELETE',
|
13
|
+
rel: 'self',
|
14
|
+
schema: schema,
|
15
|
+
targetSchema: target_schema(resource)
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def schema
|
20
|
+
{
|
21
|
+
strictProperties: true,
|
22
|
+
properties: {},
|
23
|
+
type: ['object']
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def target_schema(resource)
|
28
|
+
{
|
29
|
+
anyOf: [
|
30
|
+
resource.ref,
|
31
|
+
{ '$ref': '#/definitions/error' }
|
32
|
+
]
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
module Resource
|
5
|
+
module JsonSchema
|
6
|
+
module Links
|
7
|
+
module Member
|
8
|
+
class << self
|
9
|
+
def link(resource, action)
|
10
|
+
{
|
11
|
+
href: "#{resource.member_path}/#{action.name}",
|
12
|
+
method: action.method.upcase,
|
13
|
+
rel: 'self',
|
14
|
+
schema: schema,
|
15
|
+
targetSchema: target_schema(resource)
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def schema
|
20
|
+
{
|
21
|
+
strictProperties: true,
|
22
|
+
properties: {},
|
23
|
+
type: ['object']
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def target_schema(resource)
|
28
|
+
{
|
29
|
+
anyOf: [
|
30
|
+
resource.ref,
|
31
|
+
{ '$ref': '#/definitions/error' }
|
32
|
+
]
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|