tramway-api 1.8.1.1 → 1.8.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +66 -6
- data/app/controllers/tramway/api/application_controller.rb +3 -1
- data/app/controllers/tramway/api/v1/application_controller.rb +101 -1
- data/app/controllers/tramway/api/v1/records_controller.rb +1 -98
- data/app/serializers/tramway/api/v1/application_serializer.rb +2 -1
- data/app/serializers/tramway/api/v1/error_serializer.rb +1 -5
- data/lib/tramway/api.rb +15 -1
- data/lib/tramway/api/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 151b3c808fba04666fdb2cccbd5368d45c86c6539878c52e1c9fa93905a3eb85
|
4
|
+
data.tar.gz: 8eeaf9cde77e40c5f170c3c1d242c88025003d10176947e943ae59dd10520b25
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 989b0c66ec542b84a55f803f676b0778b78ccd012ced6579ae858c0aaa31f0d345f9ff4ea737a64e393735a37ffa6285fe153ceb862b0b1dc692a4f1f2999ee3
|
7
|
+
data.tar.gz: ac301bb8e6fc9a7dc5e8ae7a2100703977cc7d9d58a4f2c384bdb02130ed30b02b214b1c682874b4b32fdce38f33017faadfa89352b8cb4081fad439305c3d23
|
data/README.md
CHANGED
@@ -44,6 +44,7 @@ coming soon...
|
|
44
44
|
gem 'state_machine', github: 'seuros/state_machine'
|
45
45
|
gem 'knock'
|
46
46
|
gem 'audited'
|
47
|
+
gem 'ransack'
|
47
48
|
```
|
48
49
|
|
49
50
|
## Usage
|
@@ -64,10 +65,24 @@ gem 'knock'
|
|
64
65
|
|
65
66
|
Run `bundle install`
|
66
67
|
|
68
|
+
### Initialize @application object
|
69
|
+
|
70
|
+
[How-to](https://github.com/Purple-Magic/tramway-core/blob/develop/README.md#every-tramway-application-need-initialized-application-object-or-if-you-create-tramway-plugin-it-should-be-application_engine-object)
|
71
|
+
|
72
|
+
*config/routes.rb*
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
Rails.application.routes.draw do
|
76
|
+
# ...
|
77
|
+
mount Tramway::Api::Engine, at: '/api'
|
78
|
+
# ...
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
67
82
|
Then generate User (you use another name, it's just an example) model
|
68
83
|
|
69
84
|
```
|
70
|
-
rails g model user email:text password_digest:text username:text state:text
|
85
|
+
rails g model user email:text password_digest:text username:text state:text uuid:uuid
|
71
86
|
```
|
72
87
|
|
73
88
|
Enable extension in your database:
|
@@ -100,11 +115,26 @@ class User < Tramway::Core::ApplicationRecord
|
|
100
115
|
end
|
101
116
|
```
|
102
117
|
|
103
|
-
Create file `config/initializers/tramway.rb`
|
118
|
+
#### Create file `config/initializers/tramway.rb`
|
119
|
+
#### If you need JWT authentication add this line to the `config/initializers/tramway.rb`
|
104
120
|
|
105
121
|
```ruby
|
106
122
|
::Tramway::Api.auth_config = { user_model: User, auth_attributes: %i[email username] }
|
107
|
-
|
123
|
+
```
|
124
|
+
|
125
|
+
#### Configurate available models. Tramway will create end points according to this config
|
126
|
+
|
127
|
+
```
|
128
|
+
::Tramway::Api.set_available_models({
|
129
|
+
User => [
|
130
|
+
{
|
131
|
+
show: lambda do |record, current_user|
|
132
|
+
record.id == current_user.id # shows only current_user profile
|
133
|
+
end
|
134
|
+
}
|
135
|
+
],
|
136
|
+
project: :your_project_name
|
137
|
+
})
|
108
138
|
```
|
109
139
|
|
110
140
|
Run `rails g tramway:core:install`
|
@@ -316,7 +346,7 @@ Create serializer
|
|
316
346
|
*app/serializers/user_serializer.rb*
|
317
347
|
|
318
348
|
```ruby
|
319
|
-
class UserSerializer < Tramway::
|
349
|
+
class UserSerializer < Tramway::Api::V1::ApplicationSerializer
|
320
350
|
attributes :username, :email
|
321
351
|
end
|
322
352
|
```
|
@@ -353,9 +383,39 @@ Docs coming soon
|
|
353
383
|
|
354
384
|
### Show
|
355
385
|
|
356
|
-
|
386
|
+
#### Description
|
357
387
|
|
358
|
-
|
388
|
+
It returns just one record, if it is not deleted.
|
389
|
+
|
390
|
+
#### Using
|
391
|
+
|
392
|
+
##### Allow method show in tramway initializer for `YourModel`
|
393
|
+
|
394
|
+
*config/initializers/tramway.rb*
|
395
|
+
|
396
|
+
```ruby
|
397
|
+
::Tramway::Api.set_available_models({ YourModel => [ :show ] }, project: :your_project_name })
|
398
|
+
```
|
399
|
+
|
400
|
+
##### Create serializer
|
401
|
+
|
402
|
+
*app/serializers/user_serializer.rb*
|
403
|
+
|
404
|
+
```ruby
|
405
|
+
class UserSerializer < Tramway::Core::ApplicationSerializer
|
406
|
+
attributes :username, :email
|
407
|
+
end
|
408
|
+
```
|
409
|
+
|
410
|
+
##### Run your server on the localhost `rails s`
|
411
|
+
##### Made this query to test new API method (for example: you can create file `bin/test_tramway.rb` with this lines):
|
412
|
+
|
413
|
+
```ruby
|
414
|
+
require 'net/http'
|
415
|
+
|
416
|
+
YourModel.create! attribute_1: 'some value', attribute_2: 'some_value'
|
417
|
+
Net::HTTP.get('localhost:3000', "/api/v1/records/#{YourModel.last.id}?model=YourModel")
|
418
|
+
```
|
359
419
|
|
360
420
|
### Destroy
|
361
421
|
|
@@ -58,7 +58,9 @@ module Tramway
|
|
58
58
|
|
59
59
|
def current_user
|
60
60
|
Tramway::Api.user_based_models.map do |user_based_model|
|
61
|
-
|
61
|
+
unless user_based_model == User
|
62
|
+
send("current_#{user_based_model.name.underscore}")
|
63
|
+
end
|
62
64
|
end.compact.first
|
63
65
|
end
|
64
66
|
end
|
@@ -15,10 +15,110 @@ module Tramway
|
|
15
15
|
def snake_case(params)
|
16
16
|
hash = {}
|
17
17
|
params.each do |attribute, value|
|
18
|
-
|
18
|
+
key = UUID.validate(attribute) ? attribute : attribute.to_s.gsub('-', '_')
|
19
|
+
hash.merge! key => value
|
19
20
|
end
|
20
21
|
hash
|
21
22
|
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def record
|
27
|
+
id_method = Tramway::Api.id_method_of(model: model_class) || :uuid
|
28
|
+
@record = model_class.find_by! id_method => params[:id] if params[:id].present?
|
29
|
+
end
|
30
|
+
|
31
|
+
def records
|
32
|
+
collection = model_class.active.order(id: :desc).send params[:scope] || :all
|
33
|
+
collection = collection.full_text_search params[:search] if params[:search]
|
34
|
+
collection
|
35
|
+
end
|
36
|
+
|
37
|
+
def check_available_model_class
|
38
|
+
unless model_class
|
39
|
+
head(:unauthorized) && return unless current_user
|
40
|
+
head(:unprocessable_entity) && return
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def check_available_model_action_for_record
|
45
|
+
action_is_available = check_action
|
46
|
+
action_is_available.tap do
|
47
|
+
if action_is_available.is_a?(Proc) && !action_is_available.call(record, current_user)
|
48
|
+
head(:unprocessable_entity) && return
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def available_action_for_collection
|
54
|
+
action_is_available = check_action
|
55
|
+
return records if action_is_available == true
|
56
|
+
|
57
|
+
action_is_available.call records, current_user if action_is_available.is_a?(Proc)
|
58
|
+
end
|
59
|
+
|
60
|
+
def check_action
|
61
|
+
action_is_available = checking_roles.map do |role|
|
62
|
+
Tramway::Api.action_is_available(
|
63
|
+
action: action_name.to_sym,
|
64
|
+
project: (@application_engine || @application.name),
|
65
|
+
role: role,
|
66
|
+
model_name: params[:model],
|
67
|
+
current_user: current_user
|
68
|
+
)
|
69
|
+
end.compact.uniq - [false]
|
70
|
+
|
71
|
+
if action_is_available.count > 1
|
72
|
+
Tramway::Error.raise_error(:tramway, :api, :api, :v1, :records_controller, :available_action_for_collection, :duplicate_actions)
|
73
|
+
end
|
74
|
+
|
75
|
+
action_is_available = action_is_available.first
|
76
|
+
|
77
|
+
action_is_available.tap do
|
78
|
+
head(:unprocessable_entity) && return unless action_is_available
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def authenticate_user_if_needed
|
83
|
+
action_is_open = Tramway::Api.action_is_available(
|
84
|
+
action: action_name.to_sym,
|
85
|
+
project: (@application_engine || @application.name),
|
86
|
+
model_name: params[:model]
|
87
|
+
)
|
88
|
+
head(:unauthorized) && return if !current_user && !action_is_open
|
89
|
+
end
|
90
|
+
|
91
|
+
def available_models_for_current_user
|
92
|
+
checking_roles.reduce([]) do |models, role|
|
93
|
+
models += ::Tramway::Api.available_models(role: role).map(&:to_s)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def checking_roles
|
98
|
+
[:open, current_user&.role].compact
|
99
|
+
end
|
100
|
+
|
101
|
+
protected
|
102
|
+
|
103
|
+
def model_class
|
104
|
+
begin
|
105
|
+
params[:model].constantize
|
106
|
+
rescue ActiveSupport::Concern::MultipleIncludedBlocks => e
|
107
|
+
raise "#{e}. Maybe #{params[:model]} model doesn't exists or there is naming conflicts with it"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def decorator_class(model_name = nil)
|
112
|
+
"#{model_name || model_class}Decorator".constantize
|
113
|
+
end
|
114
|
+
|
115
|
+
def form_class(model_name = nil)
|
116
|
+
"#{model_name || model_class}Form".constantize
|
117
|
+
end
|
118
|
+
|
119
|
+
def serializer_class(model_name = nil)
|
120
|
+
"#{model_name || model_class}Serializer".constantize
|
121
|
+
end
|
22
122
|
end
|
23
123
|
end
|
24
124
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Tramway::Api::V1
|
4
4
|
class RecordsController < ::Tramway::Api::V1::ApplicationController
|
5
5
|
before_action :check_available_model_class
|
6
|
-
before_action :check_available_model_action_for_record, only: [
|
6
|
+
before_action :check_available_model_action_for_record, only: %i[show update destroy]
|
7
7
|
before_action :authenticate_user_if_needed
|
8
8
|
|
9
9
|
def index
|
@@ -54,102 +54,5 @@ module Tramway::Api::V1
|
|
54
54
|
include: '*',
|
55
55
|
status: :no_content
|
56
56
|
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
def record
|
61
|
-
if params[:id].present?
|
62
|
-
@record = model_class.find_by! uuid: params[:id]
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def records
|
67
|
-
collection = model_class.active.order(id: :desc).send params[:scope] || :all
|
68
|
-
collection = collection.full_text_search params[:search] if params[:search]
|
69
|
-
collection
|
70
|
-
end
|
71
|
-
|
72
|
-
def check_available_model_class
|
73
|
-
unless model_class
|
74
|
-
head(:unauthorized) && return unless current_user
|
75
|
-
head(:unprocessable_entity) && return
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def check_available_model_action_for_record
|
80
|
-
action_is_available = check_action
|
81
|
-
action_is_available.tap do
|
82
|
-
head(:unprocessable_entity) && return if action_is_available.is_a?(Proc) && !action_is_available.call(record, current_user)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def available_action_for_collection
|
87
|
-
action_is_available = check_action
|
88
|
-
return records if action_is_available == true
|
89
|
-
action_is_available.call records, current_user if action_is_available.is_a?(Proc)
|
90
|
-
end
|
91
|
-
|
92
|
-
def check_action
|
93
|
-
action_is_available = checking_roles.map do |role|
|
94
|
-
Tramway::Api.action_is_available(
|
95
|
-
action: action_name.to_sym,
|
96
|
-
project: (@application_engine || @application.name),
|
97
|
-
role: role,
|
98
|
-
model_name: params[:model],
|
99
|
-
current_user: current_user
|
100
|
-
)
|
101
|
-
end.compact.uniq - [false]
|
102
|
-
|
103
|
-
if action_is_available.count > 1
|
104
|
-
Tramway::Error.raise_error(:tramway, :api, :api, :v1, :records_controller, :available_action_for_collection, :duplicate_actions)
|
105
|
-
end
|
106
|
-
|
107
|
-
action_is_available = action_is_available.first
|
108
|
-
|
109
|
-
action_is_available.tap do
|
110
|
-
head(:unprocessable_entity) && return unless action_is_available
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def authenticate_user_if_needed
|
115
|
-
action_is_open = Tramway::Api.action_is_available(
|
116
|
-
action: action_name.to_sym,
|
117
|
-
project: (@application_engine || @application.name),
|
118
|
-
model_name: params[:model]
|
119
|
-
)
|
120
|
-
head(:unauthorized) && return if !current_user && !action_is_open
|
121
|
-
end
|
122
|
-
|
123
|
-
def model_class
|
124
|
-
if params[:model].to_s.in? available_models_for_current_user
|
125
|
-
begin
|
126
|
-
params[:model].constantize
|
127
|
-
rescue ActiveSupport::Concern::MultipleIncludedBlocks => e
|
128
|
-
raise "#{e}. Maybe #{params[:model]} model doesn't exists or there is naming conflicts with it"
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def available_models_for_current_user
|
134
|
-
checking_roles.reduce([]) do |models, role|
|
135
|
-
models += ::Tramway::Api.available_models(role: role).map(&:to_s)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def checking_roles
|
140
|
-
[ :open, current_user&.role ].compact
|
141
|
-
end
|
142
|
-
|
143
|
-
def decorator_class(model_name = nil)
|
144
|
-
"#{model_name || model_class}Decorator".constantize
|
145
|
-
end
|
146
|
-
|
147
|
-
def form_class(model_name = nil)
|
148
|
-
"#{model_name || model_class}Form".constantize
|
149
|
-
end
|
150
|
-
|
151
|
-
def serializer_class(model_name = nil)
|
152
|
-
"#{model_name || model_class}Serializer".constantize
|
153
|
-
end
|
154
57
|
end
|
155
58
|
end
|
@@ -27,12 +27,8 @@ class Tramway::Api::V1::ErrorSerializer < ActiveModel::Serializer
|
|
27
27
|
end
|
28
28
|
|
29
29
|
object.model&.attributes&.each do |attribute_key, attribute_value|
|
30
|
-
if attribute_value.is_a?(
|
31
|
-
error_messages.merge!(error_messages(attribute_value, path + [attribute_key]))
|
32
|
-
elsif attribute_value.is_a?(Array)
|
30
|
+
if attribute_value.is_a?(Array)
|
33
31
|
attribute_value.each_with_index do |array_attribute_value, array_attribute_key|
|
34
|
-
next unless array_attribute_value.is_a?(Reform::Form)
|
35
|
-
|
36
32
|
error_messages.merge!(
|
37
33
|
error_messages(
|
38
34
|
array_attribute_value,
|
data/lib/tramway/api.rb
CHANGED
@@ -56,7 +56,10 @@ module Tramway
|
|
56
56
|
|
57
57
|
def action_is_available(project:, role: :open, model_name:, action:, current_user: nil)
|
58
58
|
actions = select_actions(project: project, role: role, model_name: model_name)
|
59
|
-
|
59
|
+
if actions.present? && !actions.is_a?(Array)
|
60
|
+
raise "Looks like you did not used array type to define action permissions. Remember it should be this way: `#{model_name} => [ :#{action} ]` or `#{model_name} => [ { #{action}: lambda { |record, current_user| your_condition } } ]`"
|
61
|
+
end
|
62
|
+
|
60
63
|
availability = actions&.select do |a|
|
61
64
|
if a.is_a? Symbol
|
62
65
|
a == action.to_sym
|
@@ -80,6 +83,17 @@ module Tramway
|
|
80
83
|
new_hash.merge! pair[0].to_s => pair[1]
|
81
84
|
end
|
82
85
|
end
|
86
|
+
|
87
|
+
def id_methods_of(options = {})
|
88
|
+
@@id_methods ||= {}
|
89
|
+
@@id_methods.merge!(options.reduce({}) do |hash, pair|
|
90
|
+
hash.merge! pair[0].to_s => pair[1]
|
91
|
+
end)
|
92
|
+
end
|
93
|
+
|
94
|
+
def id_method_of(model:)
|
95
|
+
@@id_methods[model.to_s]
|
96
|
+
end
|
83
97
|
end
|
84
98
|
end
|
85
99
|
end
|
data/lib/tramway/api/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tramway-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.8.
|
4
|
+
version: 1.8.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pavel Kalashnikov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-06-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: active_model_serializers
|