model_driven_api 3.1.1 → 3.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b2e60735be9ed9050c42d522a30c5e441bd649cf8447f0313b717e04c0186ce
4
- data.tar.gz: 29607e7fc184665bcab771c1889745e21f87973aff976c8865bbe0f714f249c2
3
+ metadata.gz: fe66f672447c0aa658740f932e8245bf57a02fc0531e79520e5c426410e2c9a3
4
+ data.tar.gz: 131b5eb93497c89b0d03506398e6beb2ac3b2fb5b74d8af19b7488151eb4b1cd
5
5
  SHA512:
6
- metadata.gz: 84e9365bf07f643ef2bf78055902f538f77d06301c7ba1e888cfd6773bfa381791d861d13ffa46f3448f58426f954522e9187f1d70aec48f3622d801f93c6615
7
- data.tar.gz: 1db187f6b765a5cb0bd0c1b2f0ee0f33883c9f4c3a5dabad32eaeda8488d57d386ddd71094b3a632c2b1222d04e421e95ba25d3be4eba3c5d13a25746e7b2ff0
6
+ metadata.gz: 22ddc373d73b8c08c0dd44f735c7c8faccea38850557d51418ca1d07e4cb9eb393df2fb9fa51f491074cefec20a55b4ede0c98eff1dbfbd8d8081e56c935ebcd
7
+ data.tar.gz: 103e01d9c18ab24e997bf10b2212cc8fddf56fbc3764c591ce72444aacb79c1b75c139e02d5bf74b825dc25839df0c4182d60c9417d515ea266ee2f505e5cfc6
@@ -1,7 +1,7 @@
1
1
  # require 'model_driven_api/version'
2
2
  class Api::V2::InfoController < Api::V2::ApplicationController
3
3
  # Info uses a different auth method: username and password
4
- skip_before_action :authenticate_request, only: [:version], raise: false
4
+ skip_before_action :authenticate_request, only: [:version, :swagger, :openapi], raise: false
5
5
  skip_before_action :extract_model
6
6
 
7
7
  # api :GET, '/api/v2/info/version', "Just prints the APPVERSION."
@@ -57,13 +57,760 @@ class Api::V2::InfoController < Api::V2::ApplicationController
57
57
  render json: pivot.to_json, status: 200
58
58
  end
59
59
 
60
+ def compute_type(model, key)
61
+ # if it's a file, a date or a text, then return string
62
+ instance = model.new
63
+ # If it's a method, it is a peculiar case, in which we have to return "object" and additionalProperties: true
64
+ return "method" if model.methods.include?(:json_attrs) && model.json_attrs && model.json_attrs.include?(:methods) && model.json_attrs[:methods].include?(key.to_sym)
65
+ # If it's not the case of a method, then it's a field
66
+ method_class = instance.send(key).class.to_s
67
+ method_key = model.columns_hash[key]
68
+
69
+ # Not columns
70
+ return "object" if method_class == "ActiveStorage::Attached::One"
71
+ return "array" if method_class == "ActiveStorage::Attached::Many" || method_class == "Array" || method_class.ends_with?("Array") || method_class.ends_with?("Collection") || method_class.ends_with?("Relation") || method_class.ends_with?("Set") || method_class.ends_with?("List") || method_class.ends_with?("Queue") || method_class.ends_with?("Stack") || method_class.ends_with?("ActiveRecord_Associations_CollectionProxy")
72
+
73
+ # Columns
74
+ case method_key.type
75
+ when :json, :jsonb
76
+ return "object"
77
+ when :enum
78
+ return "array"
79
+ when :text, :hstore
80
+ return "string"
81
+ when :decimal, :float, :bigint
82
+ return "number"
83
+ end
84
+ method_key.type.to_s
85
+ end
86
+
87
+ def create_properties_from_model(model, dsl)
88
+ JSON.parse(model.new.to_json(dsl)).keys.map do |k|
89
+ # Rails.logger.debug "###################### Model #{model.model_name.human rescue ""} Key #{k}"
90
+ type = compute_type(model, k)
91
+ # Rails.logger.debug "###################### Model #{model.model_name.human rescue ""} Type for #{k} is #{type}"
92
+ if type == "method"
93
+ [k, { "type": "object", "additionalProperties": true }]
94
+ elsif type == "date"
95
+ [k, { "type": "string", "format": "date" }]
96
+ elsif type == "datetime"
97
+ [k, { "type": "string", "format": "date-time" }]
98
+ elsif type == "object" && (k.classify.constantize rescue false)
99
+ sub_model = k.classify.constantize
100
+ properties = dsl[:include].present? && dsl[:include].include?(k) ? create_properties_from_model(sub_model, dsl[:include][k.to_sym]) : create_properties_from_model(sub_model, {})
101
+ [k, { "type": "object", "properties": properties }] rescue nil
102
+ elsif type == "array" && (k.classify.constantize rescue false)
103
+ sub_model = k.classify.constantize
104
+ properties = dsl[:include].present? && dsl[:include].include?(k) ? create_properties_from_model(sub_model, dsl[:include][k.to_sym]) : create_properties_from_model(sub_model, {})
105
+ [k, { "type": "array", "items": { "type": "object", "properties": properties } }] rescue nil
106
+ else
107
+ [k, { "type": type }]
108
+ end
109
+ end.compact.to_h
110
+ end
111
+
112
+ def generate_paths
113
+ pivot = {
114
+ "/authenticate": {
115
+ "post": {
116
+ "summary": "Authenticate",
117
+ "tags": ["Authentication"],
118
+ "description": "Authenticate the user and return a JWT token in the header and the current user as body",
119
+ "security": [
120
+ "basicAuth": []
121
+ ],
122
+ "requestBody": {
123
+ "content": {
124
+ "application/json": {
125
+ "schema": {
126
+ "type": "object",
127
+ "properties": {
128
+ "auth": {
129
+ "type": "object",
130
+ "properties": {
131
+ "email": {
132
+ "type": "string",
133
+ "format": "email"
134
+ },
135
+ "password": {
136
+ "type": "string",
137
+ "format": "password"
138
+ }
139
+ }
140
+ }
141
+ },
142
+ "required": ["email", "password"]
143
+ }
144
+ }
145
+ }
146
+ },
147
+ "responses": {
148
+ "200": {
149
+ "description": "User authenticated",
150
+ "headers": {
151
+ "token": {
152
+ "description": "JWT",
153
+ "schema": {
154
+ "type": "string"
155
+ }
156
+ }
157
+ },
158
+ "content": {
159
+ "application/json": {
160
+ "schema": {
161
+ "type": "object",
162
+ # ["id", "email", "created_at", "admin", "locked", "supplier_id", "location_id", "roles"]
163
+ "properties": create_properties_from_model(User, User.json_attrs)
164
+ }
165
+ }
166
+ }
167
+ },
168
+ "401": {
169
+ "description": "Unauthorized"
170
+ }
171
+ }
172
+ }
173
+ },
174
+ "/info/version": {
175
+ "get": {
176
+ "summary": "Version",
177
+ "description": "Just prints the APPVERSION",
178
+ "tags": ["Info"],
179
+ "responses": {
180
+ "200": {
181
+ "description": "APPVERSION",
182
+ "content": {
183
+ "application/json": {
184
+ "schema": {
185
+ "type": "string"
186
+ }
187
+ }
188
+ }
189
+ }
190
+ }
191
+ }
192
+ },
193
+ "/info/heartbeat": {
194
+ "get": {
195
+ "summary": "Heartbeat",
196
+ "description": "Just keeps the session alive by returning a new token",
197
+ "tags": ["Info"],
198
+ "security": [
199
+ "bearerAuth": []
200
+ ],
201
+ "responses": {
202
+ "200": {
203
+ "description": "Session alive",
204
+ "headers": {
205
+ "token": {
206
+ "description": "JWT",
207
+ "schema": {
208
+ "type": "string"
209
+ }
210
+ }
211
+ }
212
+ }
213
+ }
214
+ }
215
+ },
216
+ "/info/roles": {
217
+ "get": {
218
+ "summary": "Roles",
219
+ "description": "Returns the roles list",
220
+ "tags": ["Info"],
221
+ "security": [
222
+ "bearerAuth": []
223
+ ],
224
+ "responses": {
225
+ "200": {
226
+ "description": "Roles list",
227
+ "content": {
228
+ "application/json": {
229
+ "schema": {
230
+ "type": "array",
231
+ "items": {
232
+ "type": "object",
233
+ "properties": {
234
+ "id": {
235
+ "type": "integer"
236
+ },
237
+ "name": {
238
+ "type": "string"
239
+ },
240
+ "description": {
241
+ "type": "string"
242
+ }
243
+ }
244
+ }
245
+ }
246
+ }
247
+ }
248
+ }
249
+ }
250
+ }
251
+ },
252
+ "/info/schema": {
253
+ "get": {
254
+ "summary": "Schema",
255
+ "description": "Returns the schema of the models",
256
+ "tags": ["Info"],
257
+ "security": [
258
+ "bearerAuth": []
259
+ ],
260
+ "responses": {
261
+ "200": {
262
+ "description": "Schema of the models",
263
+ "content": {
264
+ "application/json": {
265
+ "schema": {
266
+ "type": "array",
267
+ "items": {
268
+ "type": "object",
269
+ "properties": {
270
+ "id": {
271
+ "type": "integer"
272
+ },
273
+ "created_at": {
274
+ "type": "string",
275
+ "format": "date-time"
276
+ },
277
+ "updated_at": {
278
+ "type": "string",
279
+ "format": "date-time"
280
+ },
281
+ }
282
+ }
283
+ }
284
+ }
285
+ }
286
+ }
287
+ }
288
+ }
289
+ },
290
+ "/info/dsl": {
291
+ "get": {
292
+ "summary": "DSL",
293
+ "description": "Returns the DSL of the models",
294
+ "tags": ["Info"],
295
+ "security": [
296
+ "bearerAuth": []
297
+ ],
298
+ "responses": {
299
+ "200": {
300
+ "description": "DSL of the models",
301
+ "content": {
302
+ "application/json": {
303
+ "schema": {
304
+ "type": "object",
305
+ "properties": {
306
+ "id": {
307
+ "type": "integer"
308
+ },
309
+ "created_at": {
310
+ "type": "string",
311
+ "format": "date-time"
312
+ },
313
+ "updated_at": {
314
+ "type": "string",
315
+ "format": "date-time"
316
+ }
317
+ }
318
+ }
319
+ }
320
+ }
321
+ }
322
+ }
323
+ }
324
+ },
325
+ "/info/translations": {
326
+ "get": {
327
+ "summary": "Translations",
328
+ "description": "Returns the translations of the entire App",
329
+ "tags": ["Info"],
330
+ "security": [
331
+ "bearerAuth": []
332
+ ],
333
+ "responses": {
334
+ "200": {
335
+ "description": "Translations",
336
+ "content": {
337
+ "application/json": {
338
+ "schema": {
339
+ "type": "object",
340
+ "properties": {
341
+ "key": {
342
+ "type": "string"
343
+ },
344
+ "value": {
345
+ "type": "string"
346
+ }
347
+ }
348
+ }
349
+ }
350
+ }
351
+ }
352
+ }
353
+ }
354
+ },
355
+ "/info/settings": {
356
+ "get": {
357
+ "summary": "Settings",
358
+ "description": "Returns the settings of the App",
359
+ "tags": ["Info"],
360
+ "security": [
361
+ "bearerAuth": []
362
+ ],
363
+ "responses": {
364
+ "200": {
365
+ "description": "Settings",
366
+ "content": {
367
+ "application/json": {
368
+ "schema": {
369
+ "type": "object",
370
+ "properties": {
371
+ "ns": {
372
+ "type": "object",
373
+ "properties": {
374
+ "key": {
375
+ "type": "string"
376
+ },
377
+ "value": {
378
+ "type": "string"
379
+ }
380
+ }
381
+ }
382
+ }
383
+ }
384
+ }
385
+ }
386
+ }
387
+ }
388
+ }
389
+ },
390
+ "/info/swagger": {
391
+ "get": {
392
+ "summary": "Swagger",
393
+ "description": "Returns the Swagger",
394
+ "tags": ["Info"],
395
+ "responses": {
396
+ "200": {
397
+ "description": "Swagger",
398
+ "content": {
399
+ "application/json": {
400
+ "schema": {
401
+ "type": "object",
402
+ "properties": {
403
+ "id": {
404
+ "type": "integer"
405
+ },
406
+ "created_at": {
407
+ "type": "string",
408
+ "format": "date-time"
409
+ },
410
+ "updated_at": {
411
+ "type": "string",
412
+ "format": "date-time"
413
+ }
414
+ }
415
+ }
416
+ }
417
+ }
418
+ }
419
+ }
420
+ }
421
+ }
422
+ }
423
+ ApplicationRecord.subclasses.each do |d|
424
+ # Only if current user can read the model
425
+ if true # can? :read, d
426
+ model = d.to_s.underscore.tableize
427
+ # CRUD and Search endpoints
428
+ pivot["/#{model}"] = {
429
+ "get": {
430
+ "summary": "Index",
431
+ "description": "Returns the list of #{model}",
432
+ "tags": [model.classify],
433
+ "security": [
434
+ "bearerAuth": []
435
+ ],
436
+ "responses": {
437
+ "200": {
438
+ "description": "List of #{model}",
439
+ "content": {
440
+ "application/json": {
441
+ "schema": {
442
+ "type": "array",
443
+ "items": {
444
+ "type": "object",
445
+ "properties": create_properties_from_model(d, (d.json_attrs rescue {}))
446
+ }
447
+ }
448
+ }
449
+ }
450
+ },
451
+ "404": {
452
+ "description": "No #{model} found"
453
+ }
454
+ }
455
+ },
456
+ "post": {
457
+ "summary": "Create",
458
+ "description": "Creates a new #{model}",
459
+ "tags": [model.classify],
460
+ "security": [
461
+ "bearerAuth": []
462
+ ],
463
+ "requestBody": {
464
+ "content": {
465
+ "application/json": {
466
+ "schema": {
467
+ "type": "object",
468
+ "properties": {
469
+ "#{model.singularize}": {
470
+ "type": "object",
471
+ "properties": create_properties_from_model(d, (d.json_attrs rescue {}))
472
+ }
473
+ }
474
+ }
475
+ }
476
+ }
477
+ },
478
+ "responses": {
479
+ "200": {
480
+ "description": "#{model} Created",
481
+ "content": {
482
+ "application/json": {
483
+ "schema": {
484
+ "type": "object",
485
+ "properties": create_properties_from_model(d, (d.json_attrs rescue {}))
486
+ }
487
+ }
488
+ }
489
+ }
490
+ }
491
+ }
492
+ }
493
+ # Non CRUD or Search, but custom, usually bulk operations endpoints
494
+ custom_actions = d.methods(false).select do |m| m.to_s.starts_with?("custom_action_") end
495
+ custom_actions.each do |action|
496
+ custom_action_name = action.to_s.gsub("custom_action_", "")
497
+ pivot["/#{model}/custom_action/#{custom_action_name}"] = {
498
+ "post": {
499
+ "summary": "Custom Action #{custom_action_name.titleize}",
500
+ "description": "This is just an example of a custom action, they can accept a wide range of payloads and response with a wide range of responses, also all verbs are valid. Please refer to the documentation for more information.",
501
+ "tags": [model.classify],
502
+ "security": [
503
+ "bearerAuth": []
504
+ ],
505
+ "responses": {
506
+ "200": {
507
+ "description": "Custom Action",
508
+ "content": {
509
+ "application/json": {
510
+ "schema": {
511
+ "type": "object",
512
+ "properties": {
513
+ "id": {
514
+ "type": "integer"
515
+ },
516
+ "created_at": {
517
+ "type": "string",
518
+ "format": "date-time"
519
+ },
520
+ "updated_at": {
521
+ "type": "string",
522
+ "format": "date-time"
523
+ }
524
+ }
525
+ }
526
+ }
527
+ }
528
+ },
529
+ "404": {
530
+ "description": "No #{model} found"
531
+ }
532
+ }
533
+ }
534
+ }
535
+ end
536
+ pivot["/#{model}/search"] = {
537
+ # Complex queries are made using ranskac search via a post endpoint
538
+ "post": {
539
+ "summary": "Search",
540
+ "description": "Searches the #{model} using complex queries. Please refer to the [documentation](https://activerecord-hackery.github.io/ransack/) for the query syntax. In this swagger are presented only some examples, please refer to the complete documentation for more complex queries.\nThe primary method of searching in Ransack is by using what is known as predicates.\nPredicates are used within Ransack search queries to determine what information to match. For instance, the cont predicate will check to see if an attribute called 'name' or 'description' contains a value using a wildcard query.",
541
+ "tags": [model.classify],
542
+ "security": [
543
+ "bearerAuth": []
544
+ ],
545
+ "requestBody": {
546
+ "content": {
547
+ "application/json": {
548
+ "schema": {
549
+ "type": "object",
550
+ "properties": {
551
+ "q": {
552
+ "type": "object",
553
+ "properties": {
554
+ "name_or_description_cont": {
555
+ "type": "string"
556
+ },
557
+ "first_name_eq": {
558
+ "type": "string"
559
+ }
560
+ }
561
+ }
562
+ }
563
+ }
564
+ }
565
+ }
566
+ },
567
+ "responses": {
568
+ "200": {
569
+ "description": "List of #{model}",
570
+ "content": {
571
+ "application/json": {
572
+ "schema": {
573
+ "type": "array",
574
+ "items": {
575
+ "type": "object",
576
+ "properties": create_properties_from_model(d, (d.json_attrs rescue {}))
577
+ }
578
+ }
579
+ }
580
+ }
581
+ },
582
+ "404": {
583
+ "description": "No #{model} found"
584
+ }
585
+ }
586
+ }
587
+ }
588
+ pivot["/#{model}/{id}"] = {
589
+ "put": {
590
+ "summary": "Update",
591
+ "description": "Updates the complete #{model}",
592
+ "parameters": [
593
+ {
594
+ "name": "id",
595
+ "in": "path",
596
+ "required": true,
597
+ "schema": {
598
+ "type": "integer"
599
+ }
600
+ }
601
+ ],
602
+ "tags": [model.classify],
603
+ "security": [
604
+ "bearerAuth": []
605
+ ],
606
+ "requestBody": {
607
+ "content": {
608
+ "application/json": {
609
+ "schema": {
610
+ "type": "object",
611
+ "properties": {
612
+ "#{model.singularize}": {
613
+ "type": "object",
614
+ "properties": create_properties_from_model(d, {})
615
+ }
616
+ }
617
+ }
618
+ }
619
+ }
620
+ },
621
+ "responses": {
622
+ "200": {
623
+ "description": "#{model} Updated",
624
+ "content": {
625
+ "application/json": {
626
+ "schema": {
627
+ "type": "object",
628
+ "properties": create_properties_from_model(d, (d.json_attrs rescue {}))
629
+ }
630
+ }
631
+ }
632
+ },
633
+ "404": {
634
+ "description": "No #{model} found"
635
+ }
636
+ }
637
+ },
638
+ "patch": {
639
+ "summary": "Patch",
640
+ "description": "Updates the partial #{model}",
641
+ "parameters": [
642
+ {
643
+ "name": "id",
644
+ "in": "path",
645
+ "required": true,
646
+ "schema": {
647
+ "type": "integer"
648
+ }
649
+ }
650
+ ],
651
+ "tags": [model.classify],
652
+ "security": [
653
+ "bearerAuth": []
654
+ ],
655
+ "requestBody": {
656
+ "content": {
657
+ "application/json": {
658
+ "schema": {
659
+ "type": "object",
660
+ "properties": {
661
+ "#{model.singularize}": {
662
+ "type": "object",
663
+ "properties": create_properties_from_model(d, {})
664
+ }
665
+ }
666
+ }
667
+ }
668
+ }
669
+ },
670
+ "responses": {
671
+ "200": {
672
+ "description": "#{model} Patched",
673
+ "content": {
674
+ "application/json": {
675
+ "schema": {
676
+ "type": "object",
677
+ "properties": create_properties_from_model(d, (d.json_attrs rescue {}))
678
+ }
679
+ }
680
+ }
681
+ },
682
+ "404": {
683
+ "description": "No #{model} found"
684
+ }
685
+ }
686
+ },
687
+ "delete": {
688
+ "summary": "Delete",
689
+ "description": "Deletes the #{model}",
690
+ "parameters": [
691
+ {
692
+ "name": "id",
693
+ "in": "path",
694
+ "required": true,
695
+ "schema": {
696
+ "type": "integer"
697
+ }
698
+ }
699
+ ],
700
+ "tags": [model.classify],
701
+ "security": [
702
+ "bearerAuth": []
703
+ ],
704
+ "responses": {
705
+ "200": {
706
+ "description": "#{model} Deleted"
707
+ },
708
+ "404": {
709
+ "description": "No #{model} found"
710
+ }
711
+ }
712
+ },
713
+ "get": {
714
+ "summary": "Show",
715
+ "description": "Shows the #{model}",
716
+ "parameters": [
717
+ {
718
+ "name": "id",
719
+ "in": "path",
720
+ "required": true,
721
+ "schema": {
722
+ "type": "integer"
723
+ }
724
+ }
725
+ ],
726
+ "tags": [model.classify],
727
+ "security": [
728
+ "bearerAuth": []
729
+ ],
730
+ "responses": {
731
+ "200": {
732
+ "description": "Show #{model}",
733
+ "content": {
734
+ "application/json": {
735
+ "schema": {
736
+ "type": "object",
737
+ "properties": create_properties_from_model(d, (d.json_attrs rescue {}))
738
+ }
739
+ }
740
+ }
741
+ },
742
+ "404": {
743
+ "description": "No #{model} found"
744
+ }
745
+ }
746
+ }
747
+ }
748
+ # d.columns_hash.each_pair do |key, val|
749
+ # pivot[model][key] = val.type unless key.ends_with? "_id"
750
+ # end
751
+ # # Only application record descendants in order to have a clean schema
752
+ # pivot[model][:associations] ||= {
753
+ # has_many: d.reflect_on_all_associations(:has_many).map { |a|
754
+ # a.name if (((a.options[:class_name].presence || a.name).to_s.classify.constantize.new.is_a? ApplicationRecord) rescue false)
755
+ # }.compact,
756
+ # belongs_to: d.reflect_on_all_associations(:belongs_to).map { |a|
757
+ # a.name if (((a.options[:class_name].presence || a.name).to_s.classify.constantize.new.is_a? ApplicationRecord) rescue false)
758
+ # }.compact
759
+ # }
760
+ # pivot[model][:methods] ||= (d.instance_methods(false).include?(:json_attrs) && !d.json_attrs.blank?) ? d.json_attrs[:methods] : nil
761
+ end
762
+ end
763
+ pivot
764
+ end
765
+
766
+ # GET '/api/v2/info/schema'
767
+ def openapi
768
+ uri = URI(request.url)
769
+ pivot = {
770
+ "openapi": "3.0.0",
771
+ "info": {
772
+ "title": "#{Settings.ns(:main).app_name} API",
773
+ "description": "Model Driven Backend [API](https://github.com/gabrieletassoni/thecore/blob/master/docs/04_REST_API.md) created to reflect the actual Active Record Models present in the project in a dynamic way",
774
+ "version": "v2"
775
+ },
776
+ "servers": [
777
+ {
778
+ # i.e. "http://localhost:3001/api/v2"
779
+ "url": "#{uri.scheme}://#{uri.host}#{":#{uri.port}" if uri.port.present?}/api/v2",
780
+ "description": "The URL at which this API responds."
781
+ }
782
+ ],
783
+ # 1) Define the security scheme type (HTTP bearer)
784
+ "components":{
785
+ "securitySchemes": {
786
+ "basicAuth": {
787
+ "type": "http",
788
+ "scheme": "basic"
789
+ },
790
+ "bearerAuth": { # arbitrary name for the security scheme
791
+ "type": "http",
792
+ "scheme": "bearer",
793
+ "bearerFormat": "JWT" # optional, arbitrary value for documentation purposes
794
+ }
795
+ }
796
+ },
797
+ # 2) Apply the security globally to all operations
798
+ "security": [
799
+ {
800
+ "bearerAuth": [] # use the same name as above
801
+ }
802
+ ],
803
+ "paths": generate_paths
804
+ }
805
+
806
+ render json: pivot.to_json, status: 200
807
+ end
808
+
809
+ alias swagger openapi
810
+
60
811
  # GET '/api/v2/info/dsl'
61
812
  def dsl
62
813
  pivot = {}
63
- # if Rails.env.development?
64
- # Rails.configuration.eager_load_namespaces.each(&:eager_load!) if Rails.version.to_i == 5 #Rails 5
65
- # Zeitwerk::Loader.eager_load_all if Rails.version.to_i >= 6 #Rails 6
66
- # end
67
814
  ApplicationRecord.subclasses.each do |d|
68
815
  # Only if current user can read the model
69
816
  if can? :read, d
@@ -1,8 +1,11 @@
1
+ require 'concerns/model_driven_api_application_record'
1
2
  require 'concerns/model_driven_api_user'
2
3
  require 'concerns/model_driven_api_role'
3
4
 
4
5
  Rails.application.configure do
5
6
  config.after_initialize do
7
+ # Fixes: https://stackoverflow.com/a/76781489
8
+ ApplicationRecord.send(:include, ModelDrivenApiApplicationRecord)
6
9
  User.send(:include, ModelDrivenApiUser)
7
10
  Role.send(:include, ModelDrivenApiRole)
8
11
  end
data/config/routes.rb CHANGED
@@ -14,6 +14,8 @@ Rails.application.routes.draw do
14
14
  get :dsl
15
15
  get :heartbeat
16
16
  get :settings
17
+ get :swagger
18
+ get :openapi
17
19
  end
18
20
 
19
21
  post "authenticate" => "authentication#authenticate"
@@ -0,0 +1,14 @@
1
+ module ModelDrivenApiApplicationRecord
2
+ extend ActiveSupport::Concern
3
+
4
+ # Fixes: https://stackoverflow.com/a/76781489
5
+ included do
6
+ def self.ransackable_attributes(auth_object = nil)
7
+ column_names + _ransackers.keys
8
+ end
9
+
10
+ def self.ransackable_associations(auth_object = nil)
11
+ reflect_on_all_associations.map { |a| a.name.to_s } + _ransackers.keys
12
+ end
13
+ end
14
+ end
@@ -1,3 +1,3 @@
1
1
  module ModelDrivenApi
2
- VERSION = "3.1.1".freeze
2
+ VERSION = "3.1.4".freeze
3
3
  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.1
4
+ version: 3.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriele Tassoni
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-26 00:00:00.000000000 Z
11
+ date: 2024-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thecore_backend_commons
@@ -58,28 +58,28 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.2'
61
+ version: '4.1'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.2'
68
+ version: '4.1'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rack-cors
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '1.1'
75
+ version: '2.0'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '1.1'
82
+ version: '2.0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: deep_merge
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -135,6 +135,7 @@ files:
135
135
  - db/migrate/20210519145438_create_used_tokens.rb
136
136
  - db/migrate/20210528111450_rename_valid_to_is_valid_in_used_token.rb
137
137
  - lib/concerns/api_exception_management.rb
138
+ - lib/concerns/model_driven_api_application_record.rb
138
139
  - lib/concerns/model_driven_api_role.rb
139
140
  - lib/concerns/model_driven_api_user.rb
140
141
  - lib/json_web_token.rb
@@ -162,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
162
163
  - !ruby/object:Gem::Version
163
164
  version: '0'
164
165
  requirements: []
165
- rubygems_version: 3.4.10
166
+ rubygems_version: 3.5.3
166
167
  signing_key:
167
168
  specification_version: 4
168
169
  summary: Convention based RoR engine which uses DB schema introspection to create