model_driven_api 3.1.6 → 3.1.8
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/controllers/api/v2/application_controller.rb +48 -30
- data/app/controllers/api/v2/info_controller.rb +26 -2
- data/app/models/concerns/endpoints/test_api.rb +5 -0
- data/app/models/test_api.rb +2 -0
- data/config/routes.rb +19 -8
- data/lib/model_driven_api/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dcceec80f10a8a7bc91a9f8f32982f6d632f8af71936e8333ffe2f47308da2f7
|
4
|
+
data.tar.gz: e6b1f3833363f78ff5884a25ac986fb47e44e322193b65e3fc90494de2ab08dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8675f05d7145638a141e358fac87bb481318f2ea868817ea578d1400e6600291bdbc1d21691277f9c11f2c498be9e2659d724d0e3038f23c706b4a5ef8a81528
|
7
|
+
data.tar.gz: c1bd46b4cd97f04f50ddef90b3394f4ffce98348f8f73f8e05ac30259c0c16319b785ceeb5f77fb17aa0bbb55ae374009d65eaae7dc1e9e860f06ee7e0ec3565
|
@@ -121,36 +121,54 @@ class Api::V2::ApplicationController < ActionController::API
|
|
121
121
|
|
122
122
|
private
|
123
123
|
|
124
|
+
## CUSTOM ACTION
|
125
|
+
# [GET|PUT|POST|DELETE] :controller?do=:custom_action
|
126
|
+
# or
|
127
|
+
# [GET|PUT|POST|DELETE] :controller/:id?do=:
|
128
|
+
# or
|
129
|
+
# [GET|PUT|POST|DELETE] :controller?do=:custom_action-token
|
130
|
+
# or
|
131
|
+
# [GET|PUT|POST|DELETE] :controller/:id?do=:custom_action-token
|
132
|
+
# or
|
133
|
+
# [GET|PUT|POST|DELETE] :controller/custom_action/:custom_action
|
134
|
+
# or
|
135
|
+
# [GET|PUT|POST|DELETE] :controller/custom_action/:custom_action/:id
|
124
136
|
def check_for_custom_action
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
params[:token] = token.presence || bearer_token
|
137
|
-
# The endpoint can be expressed in two wayy:
|
138
|
-
# 1. As a method in the model, with suffix custom_action_<custom_action>
|
139
|
-
# 2. As a module instance method in the model, like Track::Endpoints.inventory
|
140
|
-
if defined?("Endpoints::#{@model}.#{custom_action}")
|
141
|
-
# Custom endpoint exists and can be called in the sub-modules form
|
142
|
-
body, status = "Endpoints::#{@model}".constantize.send(custom_action, params)
|
143
|
-
elsif @model.respond_to?("custom_action_#{custom_action}")
|
144
|
-
body, status = @model.send("custom_action_#{custom_action}", params)
|
145
|
-
else
|
146
|
-
# Custom endpoint does not exist or cannot be called
|
147
|
-
raise NoMethodError
|
148
|
-
end
|
149
|
-
|
150
|
-
return true, body.to_json(json_attrs), status
|
137
|
+
|
138
|
+
custom_action, token = if !params[:do].blank?
|
139
|
+
# This also responds to custom actions which have the bearer token in the custom action name. A workaround to remove for some IoT devices
|
140
|
+
# Which don't support token in header or in querystring
|
141
|
+
# This is for backward compatibility and in future it can ben removed
|
142
|
+
params[:do].split("-")
|
143
|
+
elsif request.url.include? "/custom_action/"
|
144
|
+
[params[:action_name], nil]
|
145
|
+
else
|
146
|
+
# Not a custom action call
|
147
|
+
false
|
151
148
|
end
|
152
|
-
|
153
|
-
|
149
|
+
return false unless custom_action
|
150
|
+
# Poor man's solution to avoid the possibility to
|
151
|
+
# call an unwanted method in the AR Model.
|
152
|
+
|
153
|
+
# Adding some useful information to the params hash
|
154
|
+
params[:request_url] = request.url
|
155
|
+
params[:remote_ip] = request.remote_ip
|
156
|
+
params[:request_verb] = request.request_method
|
157
|
+
params[:token] = token.presence || bearer_token
|
158
|
+
# The endpoint can be expressed in two ways:
|
159
|
+
# 1. As a method in the model, with suffix custom_action_<custom_action>
|
160
|
+
# 2. As a module instance method in the model, like Track::Endpoints.inventory
|
161
|
+
if defined?("Endpoints::#{@model}.#{custom_action}")
|
162
|
+
# Custom endpoint exists and can be called in the sub-modules form
|
163
|
+
body, status = "Endpoints::#{@model}".constantize.send(custom_action, params)
|
164
|
+
elsif @model.respond_to?("custom_action_#{custom_action}")
|
165
|
+
body, status = @model.send("custom_action_#{custom_action}", params)
|
166
|
+
else
|
167
|
+
# Custom endpoint does not exist or cannot be called
|
168
|
+
raise NoMethodError
|
169
|
+
end
|
170
|
+
|
171
|
+
return true, body.to_json(json_attrs), status
|
154
172
|
end
|
155
173
|
|
156
174
|
def bearer_token
|
@@ -209,9 +227,9 @@ class Api::V2::ApplicationController < ActionController::API
|
|
209
227
|
@model = (params[:ctrl].classify.constantize rescue params[:path].split("/").first.classify.constantize rescue controller_path.classify.constantize rescue controller_name.classify.constantize rescue nil)
|
210
228
|
# Getting the body of the request if it exists, it's ok the singular or
|
211
229
|
# plural form, this helps with automatic tests with Insomnia.
|
212
|
-
@body = params[@model.model_name.singular].presence || params[@model.model_name.route_key]
|
230
|
+
@body = (params[@model.model_name.singular].presence || params[@model.model_name.route_key]) rescue params
|
213
231
|
# Only ActiveRecords can have this model caputed
|
214
|
-
return not_found! if (!@model.new.is_a?
|
232
|
+
return not_found! if (@model != TestApi && !@model.new.is_a?(ActiveRecord::Base) rescue false)
|
215
233
|
end
|
216
234
|
|
217
235
|
def check_authorization(cmd)
|
@@ -84,14 +84,36 @@ class Api::V2::InfoController < Api::V2::ApplicationController
|
|
84
84
|
method_key.type.to_s
|
85
85
|
end
|
86
86
|
|
87
|
+
def integer?(str)
|
88
|
+
true if Integer(str) rescue false
|
89
|
+
end
|
90
|
+
|
91
|
+
def number?(str)
|
92
|
+
true if Float(str) rescue false
|
93
|
+
end
|
94
|
+
|
95
|
+
def datetime?(str)
|
96
|
+
true if DateTime.parse(str) rescue false
|
97
|
+
end
|
98
|
+
|
87
99
|
def create_properties_from_model(model, dsl, remove_reserved = false)
|
88
|
-
JSON.parse(model.new.to_json(dsl))
|
100
|
+
parsed_json = JSON.parse(model.new.to_json(dsl))
|
101
|
+
parsed_json.keys.map do |k|
|
89
102
|
type = compute_type(model, k)
|
90
103
|
|
91
104
|
# Remove fields that cannot be created or updated
|
92
105
|
if remove_reserved && %w( id created_at updated_at lock_version).include?(k.to_s)
|
93
106
|
nil
|
107
|
+
elsif type == "method" && (parsed_json[k].is_a?(FalseClass) || parsed_json[k].is_a?(TrueClass))
|
108
|
+
[k, { "type": "boolean" }]
|
109
|
+
elsif type == "method" && parsed_json[k].is_a?(String) && number?(parsed_json[k])
|
110
|
+
[k, { "type": "number" }]
|
111
|
+
elsif type == "method" && parsed_json[k].is_a?(String) && integer?(parsed_json[k])
|
112
|
+
[k, { "type": "integer" }]
|
113
|
+
elsif type == "method" && parsed_json[k].is_a?(String) && datetime?(parsed_json[k])
|
114
|
+
[k, { "type": "string", "format": "date-time" }]
|
94
115
|
elsif type == "method"
|
116
|
+
# Unknown or complex format returned
|
95
117
|
[k, { "type": "object", "additionalProperties": true }]
|
96
118
|
elsif type == "date"
|
97
119
|
[k, { "type": "string", "format": "date" }]
|
@@ -422,7 +444,7 @@ class Api::V2::InfoController < Api::V2::ApplicationController
|
|
422
444
|
}
|
423
445
|
}
|
424
446
|
}
|
425
|
-
ApplicationRecord.subclasses.each do |d|
|
447
|
+
ApplicationRecord.subclasses.sort_by { |d| d.to_s }.each do |d|
|
426
448
|
# Only if current user can read the model
|
427
449
|
if true # can? :read, d
|
428
450
|
model = d.to_s.underscore.tableize
|
@@ -494,6 +516,8 @@ class Api::V2::InfoController < Api::V2::ApplicationController
|
|
494
516
|
}
|
495
517
|
# Non CRUD or Search, but custom, usually bulk operations endpoints
|
496
518
|
custom_actions = d.methods(false).select do |m| m.to_s.starts_with?("custom_action_") end
|
519
|
+
# Add also custom actions created using th enew Endpoints Interface
|
520
|
+
custom_actions += "Endpoints::#{d.model_name.name}".constantize.methods(false) rescue []
|
497
521
|
custom_actions.each do |action|
|
498
522
|
custom_action_name = action.to_s.gsub("custom_action_", "")
|
499
523
|
pivot["/#{model}/custom_action/#{custom_action_name}"] = {
|
data/config/routes.rb
CHANGED
@@ -21,19 +21,30 @@ Rails.application.routes.draw do
|
|
21
21
|
post "authenticate" => "authentication#authenticate"
|
22
22
|
post ":ctrl/search" => 'application#index'
|
23
23
|
|
24
|
+
# Add a route with placeholders for custom actions, the custom actions routes have a form like: :ctrl/custom_action/:action_name or :ctrl/custom_action/:action_name/:id
|
25
|
+
# Can have all the verbs, but the most common are: get, post, put, delete
|
26
|
+
get ":ctrl/custom_action/:action_name", to: 'application#index'
|
27
|
+
get ":ctrl/custom_action/:action_name/:id", to: 'application#show'
|
28
|
+
post ":ctrl/custom_action/:action_name", to: 'application#create'
|
29
|
+
put ":ctrl/custom_action/:action_name/:id", to: 'application#update'
|
30
|
+
patch ":ctrl/custom_action/:action_name/:id", to: 'application#update'
|
31
|
+
delete ":ctrl/custom_action/:action_name/:id", to: 'application#destroy'
|
24
32
|
# Catchall routes
|
25
|
-
# # CRUD Show
|
26
|
-
get '*path/:id', to: 'application#show'
|
27
|
-
# # CRUD Index
|
28
|
-
get '*path', to: 'application#index'
|
29
|
-
# # CRUD Create
|
30
|
-
post '*path', to: 'application#create'
|
33
|
+
# # # CRUD Show
|
34
|
+
# get '*path/:id', to: 'application#show'
|
35
|
+
# # # CRUD Index
|
36
|
+
# get '*path', to: 'application#index'
|
37
|
+
# # # CRUD Create
|
38
|
+
# post '*path', to: 'application#create'
|
31
39
|
# # CRUD Update
|
32
40
|
put '*path/:id/multi', to: 'application#update_multi'
|
33
|
-
|
41
|
+
patch '*path/:id/multi', to: 'application#update_multi'
|
42
|
+
# put '*path/:id', to: 'application#update'
|
43
|
+
# patch '*path/:id', to: 'application#patch'
|
44
|
+
|
34
45
|
# # CRUD Delete
|
35
46
|
delete '*path/:id/multi', to: 'application#destroy_multi'
|
36
|
-
delete '*path/:id', to: 'application#destroy'
|
47
|
+
# delete '*path/:id', to: 'application#destroy'
|
37
48
|
end
|
38
49
|
end
|
39
50
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: model_driven_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gabriele Tassoni
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-03-
|
11
|
+
date: 2024-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thecore_backend_commons
|
@@ -125,6 +125,8 @@ files:
|
|
125
125
|
- app/controllers/api/v2/authentication_controller.rb
|
126
126
|
- app/controllers/api/v2/info_controller.rb
|
127
127
|
- app/controllers/api/v2/users_controller.rb
|
128
|
+
- app/models/concerns/endpoints/test_api.rb
|
129
|
+
- app/models/test_api.rb
|
128
130
|
- app/models/used_token.rb
|
129
131
|
- config/initializers/after_initialize_for_model_driven_api.rb
|
130
132
|
- config/initializers/cors_api_thecore.rb
|