model_driven_api 3.6.3 → 3.7.1
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 +832 -54
- data/Rakefile +3 -0
- data/app/controllers/api/v2/application_controller.rb +24 -49
- data/app/controllers/api/v2/info_controller.rb +2 -1308
- data/app/controllers/api/v3/application_controller.rb +132 -0
- data/app/controllers/api/v3/auth/oauth_controller.rb +4 -0
- data/app/controllers/api/v3/authentication_controller.rb +2 -0
- data/app/controllers/api/v3/info_controller.rb +37 -0
- data/app/controllers/api/v3/raw_controller.rb +14 -0
- data/app/controllers/api/v3/users_controller.rb +10 -0
- data/app/models/endpoints/push_subscriber.rb +110 -0
- data/config/routes.rb +44 -0
- data/lib/api/custom_action_dispatcher.rb +41 -0
- data/lib/api/model_resolver.rb +20 -0
- data/lib/api/open_api/base.rb +91 -0
- data/lib/api/open_api/v2.rb +1238 -0
- data/lib/api/open_api/v3.rb +349 -0
- data/lib/api/resource_attribute_set.rb +25 -0
- data/lib/api/v3/serializer_factory.rb +65 -0
- data/lib/concerns/api_exception_management.rb +4 -1
- data/lib/model_driven_api/engine.rb +7 -1
- data/lib/model_driven_api/version.rb +1 -1
- data/lib/model_driven_api.rb +8 -0
- data/lib/non_crud_endpoints.rb +18 -0
- metadata +78 -8
data/Rakefile
CHANGED
|
@@ -13,7 +13,7 @@ class Api::V2::ApplicationController < ActionController::API
|
|
|
13
13
|
|
|
14
14
|
# GET :controller/
|
|
15
15
|
def index
|
|
16
|
-
authorize! :index, @model
|
|
16
|
+
authorize! :index, @model unless public_custom_action?
|
|
17
17
|
|
|
18
18
|
# Custom Action
|
|
19
19
|
status, result, status_number = check_for_custom_action
|
|
@@ -67,7 +67,7 @@ class Api::V2::ApplicationController < ActionController::API
|
|
|
67
67
|
def create
|
|
68
68
|
# Normal Create Action
|
|
69
69
|
Rails.logger.debug("Creating a new record #{@record}")
|
|
70
|
-
authorize! :create, @record.presence || @model
|
|
70
|
+
authorize! :create, @record.presence || @model unless public_custom_action?
|
|
71
71
|
# Custom Action
|
|
72
72
|
status, result, status_number = check_for_custom_action
|
|
73
73
|
return render json: result, status: (status_number.presence || 200) if status == true
|
|
@@ -127,6 +127,19 @@ class Api::V2::ApplicationController < ActionController::API
|
|
|
127
127
|
|
|
128
128
|
private
|
|
129
129
|
|
|
130
|
+
# Returns true if the current request is for a NonCrudEndpoints custom action
|
|
131
|
+
# that has been declared as public (no authentication required).
|
|
132
|
+
# Forces autoloading of the Endpoints::<Model> class so the public_action_registry
|
|
133
|
+
# is populated before authenticate_request checks it.
|
|
134
|
+
def public_custom_action?
|
|
135
|
+
return false unless request.url.include?("/custom_action/")
|
|
136
|
+
model_name = params[:ctrl].to_s.classify
|
|
137
|
+
action_name = params[:action_name].to_s
|
|
138
|
+
# Ensure the endpoint class is loaded so its public_action declarations are registered.
|
|
139
|
+
("Endpoints::#{model_name}".constantize rescue nil)
|
|
140
|
+
NonCrudEndpoints.public_action?(model_name, action_name)
|
|
141
|
+
end
|
|
142
|
+
|
|
130
143
|
## CUSTOM ACTION
|
|
131
144
|
# [GET|PUT|POST|DELETE] :controller?do=:custom_action
|
|
132
145
|
# or
|
|
@@ -140,43 +153,9 @@ class Api::V2::ApplicationController < ActionController::API
|
|
|
140
153
|
# or
|
|
141
154
|
# [GET|PUT|POST|DELETE] :controller/custom_action/:custom_action/:id
|
|
142
155
|
def check_for_custom_action
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
# This is for backward compatibility and in future it can ben removed
|
|
147
|
-
params[:do].split("-")
|
|
148
|
-
elsif request.url.include? "/custom_action/"
|
|
149
|
-
[params[:action_name], nil]
|
|
150
|
-
else
|
|
151
|
-
# Not a custom action call
|
|
152
|
-
false
|
|
153
|
-
end
|
|
154
|
-
return false unless custom_action
|
|
155
|
-
# Poor man's solution to avoid the possibility to
|
|
156
|
-
# call an unwanted method in the AR Model.
|
|
157
|
-
|
|
158
|
-
# Adding some useful information to the params hash
|
|
159
|
-
params[:request_url] = request.url
|
|
160
|
-
params[:remote_ip] = request.remote_ip
|
|
161
|
-
params[:request_verb] = request.request_method
|
|
162
|
-
params[:token] = token.presence || bearer_token
|
|
163
|
-
# The endpoint can be expressed in two ways:
|
|
164
|
-
# 1. As a method in the model, with suffix custom_action_<custom_action>
|
|
165
|
-
# 2. As a module instance method in the model, like Track::Endpoints.inventory
|
|
166
|
-
# Example:
|
|
167
|
-
# Endpoints::TestApi.new(:test, {request_verb: "POST", is_connected: "Uhhhh"}).result
|
|
168
|
-
Rails.logger.debug("Checking for custom action #{custom_action} in #{@model}")
|
|
169
|
-
if @model.respond_to?("custom_action_#{custom_action}")
|
|
170
|
-
body, status = @model.send("custom_action_#{custom_action}", params)
|
|
171
|
-
elsif ("Endpoints::#{@model}".constantize rescue false) && "Endpoints::#{@model}".constantize.instance_methods.include?(custom_action.to_sym)
|
|
172
|
-
# Custom endpoint exists and can be called in the sub-modules form
|
|
173
|
-
body, status = "Endpoints::#{@model}".constantize.new(custom_action, params).result
|
|
174
|
-
else
|
|
175
|
-
# Custom endpoint does not exist or cannot be called
|
|
176
|
-
raise NoMethodError
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
return true, body.to_json(json_attrs), status
|
|
156
|
+
dispatched, body, status = Api::CustomActionDispatcher.call(@model, params, request)
|
|
157
|
+
return false unless dispatched
|
|
158
|
+
[true, body.to_json(json_attrs), status]
|
|
180
159
|
end
|
|
181
160
|
|
|
182
161
|
def bearer_token
|
|
@@ -193,6 +172,9 @@ class Api::V2::ApplicationController < ActionController::API
|
|
|
193
172
|
end
|
|
194
173
|
|
|
195
174
|
def authenticate_request
|
|
175
|
+
# Skip auth for public NonCrudEndpoints actions (e.g. vapid_public_key).
|
|
176
|
+
return if public_custom_action?
|
|
177
|
+
|
|
196
178
|
@current_user = nil
|
|
197
179
|
Settings.ns(:security).allowed_authorization_headers.split(",").each do |header|
|
|
198
180
|
# puts "Found header #{header}: #{request.headers[header]}"
|
|
@@ -229,17 +211,10 @@ class Api::V2::ApplicationController < ActionController::API
|
|
|
229
211
|
end
|
|
230
212
|
|
|
231
213
|
def extract_model
|
|
232
|
-
|
|
233
|
-
# For any other model-less controller, the actions must be
|
|
234
|
-
# defined in the route, and must exist in the controller definition.
|
|
235
|
-
# So, if it's not an activerecord, the find model makes no sense at all
|
|
236
|
-
# thus must return 404.
|
|
237
|
-
@model = (params[:ctrl].classify.constantize rescue params[:path].split("/").first.classify.constantize rescue controller_path.classify.constantize rescue controller_name.classify.constantize rescue nil)
|
|
238
|
-
# Getting the body of the request if it exists, it's ok the singular or
|
|
239
|
-
# plural form, this helps with automatic tests with Insomnia.
|
|
214
|
+
@model = Api::ModelResolver.resolve(params, controller_path, controller_name)
|
|
240
215
|
@body = (params[@model.model_name.singular].presence || params[@model.model_name.route_key]) rescue params
|
|
241
|
-
|
|
242
|
-
|
|
216
|
+
rescue Api::ModelResolver::NotFound
|
|
217
|
+
not_found!
|
|
243
218
|
end
|
|
244
219
|
|
|
245
220
|
def check_authorization(cmd)
|