tramway-api 1.8.1.1 → 1.8.3
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/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
|