croods 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: aa04a8d021dcb13f1a16fb7e8cbff426ff88212cc2961f7b6ab37c11dec6205a
|
4
|
+
data.tar.gz: 6eaf5e2422fc7673d79af1f371bfc3d84f667beabf7725be8bfb979f56f211b5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e3c2a7f41a1684b68d97fd5b5157a0827cc4921c187de659c328762220ac2f1fe47cbf450a9240e665b7ae908ea4814f7e625d563640d305e843369aa8e8f29e
|
7
|
+
data.tar.gz: 583726e9874be44c8817d082ec6286cadec710be19eac125ee3251f1aeaacc11e2268311fd36eeb936faad066273861984602bb7205ad6a5ed323af94127d3ab
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2020 Daniel Weinmann
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Croods
|
2
|
+
Short description and motivation.
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
How to use my plugin.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'croods'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
```bash
|
21
|
+
$ gem install croods
|
22
|
+
```
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
Contribution directions go here.
|
26
|
+
|
27
|
+
## License
|
28
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rdoc/task'
|
10
|
+
|
11
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
12
|
+
rdoc.rdoc_dir = 'rdoc'
|
13
|
+
rdoc.title = 'Croods'
|
14
|
+
rdoc.options << '--line-numbers'
|
15
|
+
rdoc.rdoc_files.include('README.md')
|
16
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'bundler/gem_tasks'
|
data/lib/croods.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rack/cors'
|
4
|
+
require 'committee'
|
5
|
+
require 'devise'
|
6
|
+
require 'devise_token_auth'
|
7
|
+
require 'pundit'
|
8
|
+
require 'schema_associations'
|
9
|
+
require 'schema_auto_foreign_keys'
|
10
|
+
require 'schema_validations'
|
11
|
+
|
12
|
+
module Croods
|
13
|
+
cattr_accessor :namespaces, :json_schema, :multi_tenancy_by
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def initialize_for(*namespaces, multi_tenancy_by: nil)
|
17
|
+
self.multi_tenancy_by = multi_tenancy_by
|
18
|
+
self.namespaces = namespaces.map(&:to_s).freeze
|
19
|
+
Middleware.insert!
|
20
|
+
end
|
21
|
+
|
22
|
+
def resources
|
23
|
+
namespaces.map do |namespace|
|
24
|
+
"#{namespace.camelcase(:upper)}::Resource".constantize
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def multi_tenancy?
|
29
|
+
!multi_tenancy_by.nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
def tenant_attribute
|
33
|
+
"#{Croods.multi_tenancy_by}_id".to_sym
|
34
|
+
end
|
35
|
+
|
36
|
+
def application_controller(&block)
|
37
|
+
return unless block
|
38
|
+
|
39
|
+
application_controller_blocks << block
|
40
|
+
end
|
41
|
+
|
42
|
+
def application_controller_blocks
|
43
|
+
@application_controller_blocks ||= []
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
require 'croods/railtie'
|
49
|
+
require 'croods/model'
|
50
|
+
require 'croods/attribute'
|
51
|
+
require 'croods/controller'
|
52
|
+
require 'croods/service'
|
53
|
+
require 'croods/action'
|
54
|
+
require 'croods/policy'
|
55
|
+
require 'croods/resource'
|
56
|
+
require 'croods/routes'
|
57
|
+
require 'croods/middleware'
|
58
|
+
require 'croods/api'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
class Action
|
5
|
+
attr_accessor :name, :public, :roles, :method, :on, :block, :service
|
6
|
+
|
7
|
+
def initialize(name, **options)
|
8
|
+
self.name = name.to_sym
|
9
|
+
self.public = options[:public]
|
10
|
+
self.roles = options[:roles]
|
11
|
+
self.method = options[:method]
|
12
|
+
self.on = options[:on]
|
13
|
+
self.block = options[:block]
|
14
|
+
self.service = options[:service]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/croods/api.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
module Api
|
5
|
+
class << self
|
6
|
+
def initial_schema
|
7
|
+
File.read(File.expand_path('api/initial_schema.json', __dir__))
|
8
|
+
end
|
9
|
+
|
10
|
+
def json_schema
|
11
|
+
schema = JSON.parse(initial_schema)
|
12
|
+
|
13
|
+
Croods.resources.each do |resource|
|
14
|
+
next unless resource.table_exists?
|
15
|
+
|
16
|
+
name = resource.resource_name
|
17
|
+
schema['definitions'][name] = resource.json_schema
|
18
|
+
schema['properties'][name] = resource.ref
|
19
|
+
end
|
20
|
+
|
21
|
+
schema.deep_stringify_keys!
|
22
|
+
Committee::Drivers::HyperSchema::Driver.new.parse(schema)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://interagent.github.io/interagent-hyper-schema",
|
3
|
+
"type": [
|
4
|
+
"object"
|
5
|
+
],
|
6
|
+
"definitions": {
|
7
|
+
"error": {
|
8
|
+
"$schema": "http://json-schema.org/draft-04/hyper-schema",
|
9
|
+
"stability": "prototype",
|
10
|
+
"strictProperties": true,
|
11
|
+
"type": [
|
12
|
+
"object"
|
13
|
+
],
|
14
|
+
"definitions": {
|
15
|
+
"id": {
|
16
|
+
"readOnly": true,
|
17
|
+
"pattern": "^\\w+$",
|
18
|
+
"type": [
|
19
|
+
"string"
|
20
|
+
]
|
21
|
+
},
|
22
|
+
"message": {
|
23
|
+
"readOnly": true,
|
24
|
+
"type": [
|
25
|
+
"string"
|
26
|
+
]
|
27
|
+
},
|
28
|
+
"identity": {
|
29
|
+
"anyOf": [
|
30
|
+
{
|
31
|
+
"$ref": "#/definitions/error/definitions/id"
|
32
|
+
}
|
33
|
+
]
|
34
|
+
}
|
35
|
+
},
|
36
|
+
"links": [],
|
37
|
+
"properties": {
|
38
|
+
"id": {
|
39
|
+
"$ref": "#/definitions/error/definitions/id"
|
40
|
+
},
|
41
|
+
"message": {
|
42
|
+
"$ref": "#/definitions/error/definitions/message"
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
},
|
47
|
+
"properties": {
|
48
|
+
"error": {
|
49
|
+
"$ref": "#/definitions/error"
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
class Attribute
|
5
|
+
attr_accessor :name, :type, :null, :default, :default_function
|
6
|
+
|
7
|
+
def initialize(name, type, null: nil, default: nil, default_function: nil)
|
8
|
+
self.name = name.to_s
|
9
|
+
self.type = type
|
10
|
+
self.null = null
|
11
|
+
self.default = default
|
12
|
+
self.default_function = default_function
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'controller/actions'
|
4
|
+
require_relative 'controller/authentication'
|
5
|
+
require_relative 'controller/authorization'
|
6
|
+
require_relative 'controller/multi_tenancy'
|
7
|
+
require_relative 'controller/resource'
|
8
|
+
require_relative 'controller/model'
|
9
|
+
require_relative 'controller/member'
|
10
|
+
require_relative 'controller/collection'
|
11
|
+
require_relative 'controller/not_found'
|
12
|
+
require_relative 'controller/already_taken'
|
13
|
+
require_relative 'controller/record_invalid'
|
14
|
+
|
15
|
+
module Croods
|
16
|
+
class Controller < ActionController::API
|
17
|
+
include Authentication
|
18
|
+
include Authorization
|
19
|
+
include MultiTenancy
|
20
|
+
include Resource
|
21
|
+
include Model
|
22
|
+
include Member
|
23
|
+
include Collection
|
24
|
+
include NotFound
|
25
|
+
include AlreadyTaken
|
26
|
+
include RecordInvalid
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
class Controller < ActionController::API
|
5
|
+
module Actions
|
6
|
+
class << self
|
7
|
+
def index
|
8
|
+
lambda do
|
9
|
+
authorize model
|
10
|
+
|
11
|
+
json = execute_service(collection, params) do
|
12
|
+
collection
|
13
|
+
end
|
14
|
+
|
15
|
+
render json: json
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def show
|
20
|
+
lambda do
|
21
|
+
authorize member
|
22
|
+
|
23
|
+
json = execute_service(member, params) do
|
24
|
+
member
|
25
|
+
end
|
26
|
+
|
27
|
+
render json: json
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def create
|
32
|
+
lambda do
|
33
|
+
member = new_member
|
34
|
+
|
35
|
+
authorize member
|
36
|
+
json = execute_service(member, member_params) do
|
37
|
+
member.save!
|
38
|
+
member
|
39
|
+
end
|
40
|
+
|
41
|
+
render status: :created, json: json
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def update
|
46
|
+
lambda do
|
47
|
+
authorize member
|
48
|
+
|
49
|
+
json = execute_service(member, member_params) do
|
50
|
+
member.update!(member_params)
|
51
|
+
member
|
52
|
+
end
|
53
|
+
|
54
|
+
render json: json
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def destroy
|
59
|
+
lambda do
|
60
|
+
authorize member
|
61
|
+
json = execute_service(member, params) do
|
62
|
+
member.destroy!
|
63
|
+
end
|
64
|
+
|
65
|
+
render json: json
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
class Controller < ActionController::API
|
5
|
+
module AlreadyTaken
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
rescue_from ActiveRecord::RecordNotUnique, with: :already_taken
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def already_taken(exception)
|
15
|
+
match = exception.message.match(/\((.+)\)=\(.+\) already exists/)
|
16
|
+
attribute = match && model.human_attribute_name(match[1])
|
17
|
+
|
18
|
+
message = attribute ? "#{attribute} already taken" : 'Already taken'
|
19
|
+
|
20
|
+
render status: :unprocessable_entity, json: {
|
21
|
+
id: 'already_taken',
|
22
|
+
message: message
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
class Controller < ActionController::API
|
5
|
+
module Authentication
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
before_action :authenticate_user!, unless: :devise_controller?
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def user_params(model)
|
15
|
+
return {} unless resource.user_is_the_owner?
|
16
|
+
return {} unless model.has_attribute?(:user_id)
|
17
|
+
|
18
|
+
{ user_id: current_user&.id }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
class Controller < ActionController::API
|
5
|
+
module Authorization
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
include Pundit
|
8
|
+
|
9
|
+
included do
|
10
|
+
after_action :verify_authorized, unless: :devise_controller?
|
11
|
+
after_action :verify_policy_scoped, unless: :devise_controller?
|
12
|
+
rescue_from Pundit::NotAuthorizedError, with: :forbidden
|
13
|
+
end
|
14
|
+
|
15
|
+
def policy_scope(scope)
|
16
|
+
@_pundit_policy_scoped = true
|
17
|
+
resource.policy_scope(action_name)
|
18
|
+
.new(tenant: header_tenant, user: current_user, scope: scope).resolve
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def forbidden(exception)
|
24
|
+
render status: :forbidden, json: {
|
25
|
+
id: 'forbidden',
|
26
|
+
message: exception.message
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Croods
|
4
|
+
class Controller < ActionController::API
|
5
|
+
module Collection
|
6
|
+
protected
|
7
|
+
|
8
|
+
def collection
|
9
|
+
resource
|
10
|
+
.apply_filters(policy_scope(model), params)
|
11
|
+
.order(resource.sort_by)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|