rhino_project_core 0.20.0.alpha.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +28 -0
  4. data/Rakefile +35 -0
  5. data/app/assets/stripe_flow.png +0 -0
  6. data/app/controllers/concerns/rhino/authenticated.rb +18 -0
  7. data/app/controllers/concerns/rhino/error_handling.rb +60 -0
  8. data/app/controllers/concerns/rhino/paper_trail_whodunnit.rb +11 -0
  9. data/app/controllers/concerns/rhino/permit.rb +38 -0
  10. data/app/controllers/concerns/rhino/set_current_user.rb +13 -0
  11. data/app/controllers/rhino/account_controller.rb +34 -0
  12. data/app/controllers/rhino/active_model_extension_controller.rb +52 -0
  13. data/app/controllers/rhino/base_controller.rb +23 -0
  14. data/app/controllers/rhino/crud_controller.rb +57 -0
  15. data/app/controllers/rhino/simple_controller.rb +13 -0
  16. data/app/controllers/rhino/simple_stream_controller.rb +12 -0
  17. data/app/helpers/rhino/omniauth_helper.rb +67 -0
  18. data/app/helpers/rhino/policy_helper.rb +42 -0
  19. data/app/helpers/rhino/segment_helper.rb +62 -0
  20. data/app/models/rhino/account.rb +13 -0
  21. data/app/models/rhino/current.rb +7 -0
  22. data/app/models/rhino/user.rb +44 -0
  23. data/app/overrides/active_record/autosave_association_override.rb +18 -0
  24. data/app/overrides/active_record/delegated_type_override.rb +14 -0
  25. data/app/overrides/activestorage/direct_uploads_controller_override.rb +23 -0
  26. data/app/overrides/activestorage/redirect_controller_override.rb +21 -0
  27. data/app/overrides/activestorage/redirect_representation_controller_override.rb +21 -0
  28. data/app/overrides/devise_token_auth/confirmations_controller_override.rb +14 -0
  29. data/app/overrides/devise_token_auth/omniauth_callbacks_controller_override.rb +45 -0
  30. data/app/overrides/devise_token_auth/passwords_controller_override.rb +9 -0
  31. data/app/overrides/devise_token_auth/registrations_controller_override.rb +20 -0
  32. data/app/overrides/devise_token_auth/sessions_controller_override.rb +26 -0
  33. data/app/overrides/devise_token_auth/token_validations_controller_override.rb +18 -0
  34. data/app/policies/rhino/account_policy.rb +27 -0
  35. data/app/policies/rhino/active_storage_attachment_policy.rb +16 -0
  36. data/app/policies/rhino/admin_policy.rb +20 -0
  37. data/app/policies/rhino/base_policy.rb +72 -0
  38. data/app/policies/rhino/crud_policy.rb +109 -0
  39. data/app/policies/rhino/editor_policy.rb +12 -0
  40. data/app/policies/rhino/global_policy.rb +8 -0
  41. data/app/policies/rhino/resource_info_policy.rb +9 -0
  42. data/app/policies/rhino/user_policy.rb +20 -0
  43. data/app/policies/rhino/viewer_policy.rb +19 -0
  44. data/app/resources/rhino/info_graph.rb +41 -0
  45. data/app/resources/rhino/open_api_info.rb +108 -0
  46. data/config/routes.rb +19 -0
  47. data/db/migrate/20180101000000_devise_token_auth_create_users.rb +54 -0
  48. data/db/migrate/20180622142754_add_allow_change_password_to_users.rb +5 -0
  49. data/db/migrate/20191217010224_add_approved_to_users.rb +7 -0
  50. data/db/migrate/20200503182019_change_tokens_to_json_b.rb +9 -0
  51. data/lib/commands/rhino/module/coverage_command.rb +44 -0
  52. data/lib/commands/rhino/module/dummy_command.rb +43 -0
  53. data/lib/commands/rhino/module/new_command.rb +34 -0
  54. data/lib/commands/rhino/module/rails_command.rb +43 -0
  55. data/lib/commands/rhino/module/test_command.rb +43 -0
  56. data/lib/generators/rhino/dev/setup/setup_generator.rb +199 -0
  57. data/lib/generators/rhino/dev/setup/templates/env.client.tt +4 -0
  58. data/lib/generators/rhino/dev/setup/templates/env.root.tt +1 -0
  59. data/lib/generators/rhino/dev/setup/templates/env.server.tt +35 -0
  60. data/lib/generators/rhino/dev/setup/templates/prepare-commit-msg +17 -0
  61. data/lib/generators/rhino/install/install_generator.rb +24 -0
  62. data/lib/generators/rhino/install/templates/account.rb +4 -0
  63. data/lib/generators/rhino/install/templates/rhino.rb +24 -0
  64. data/lib/generators/rhino/install/templates/user.rb +4 -0
  65. data/lib/generators/rhino/model/model_generator.rb +96 -0
  66. data/lib/generators/rhino/module/USAGE +6 -0
  67. data/lib/generators/rhino/module/module_generator.rb +92 -0
  68. data/lib/generators/rhino/module/templates/%name%.gemspec.tt +24 -0
  69. data/lib/generators/rhino/module/templates/lib/%namespaced_name%/engine.rb.tt +18 -0
  70. data/lib/generators/rhino/module/templates/lib/generators/%namespaced_name%/install/install_generator.rb.tt +12 -0
  71. data/lib/generators/rhino/module/templates/lib/tasks/%namespaced_name%_tasks.rake.tt +13 -0
  72. data/lib/generators/rhino/module/templates/test/dummy/app/models/user.rb +4 -0
  73. data/lib/generators/rhino/module/templates/test/dummy/config/database.yml +25 -0
  74. data/lib/generators/rhino/module/templates/test/dummy/config/initializers/devise.rb +311 -0
  75. data/lib/generators/rhino/module/templates/test/dummy/config/initializers/devise_token_auth.rb +71 -0
  76. data/lib/generators/rhino/module/templates/test/test_helper.rb +54 -0
  77. data/lib/generators/rhino/policy/policy_generator.rb +33 -0
  78. data/lib/generators/rhino/policy/templates/policy.rb.tt +46 -0
  79. data/lib/generators/test_unit/rhino_policy_generator.rb +13 -0
  80. data/lib/generators/test_unit/templates/policy_test.rb.tt +57 -0
  81. data/lib/rhino/engine.rb +166 -0
  82. data/lib/rhino/omniauth/strategies/azure_o_auth2.rb +16 -0
  83. data/lib/rhino/resource/active_model_extension/backing_store/google_sheet.rb +89 -0
  84. data/lib/rhino/resource/active_model_extension/backing_store.rb +33 -0
  85. data/lib/rhino/resource/active_model_extension/describe.rb +38 -0
  86. data/lib/rhino/resource/active_model_extension/params.rb +70 -0
  87. data/lib/rhino/resource/active_model_extension/properties.rb +231 -0
  88. data/lib/rhino/resource/active_model_extension/reference.rb +50 -0
  89. data/lib/rhino/resource/active_model_extension/routing.rb +15 -0
  90. data/lib/rhino/resource/active_model_extension/serialization.rb +16 -0
  91. data/lib/rhino/resource/active_model_extension.rb +38 -0
  92. data/lib/rhino/resource/active_record_extension/describe.rb +44 -0
  93. data/lib/rhino/resource/active_record_extension/params.rb +213 -0
  94. data/lib/rhino/resource/active_record_extension/properties.rb +85 -0
  95. data/lib/rhino/resource/active_record_extension/properties_describe.rb +228 -0
  96. data/lib/rhino/resource/active_record_extension/reference.rb +50 -0
  97. data/lib/rhino/resource/active_record_extension/routing.rb +21 -0
  98. data/lib/rhino/resource/active_record_extension/search.rb +23 -0
  99. data/lib/rhino/resource/active_record_extension/serialization.rb +16 -0
  100. data/lib/rhino/resource/active_record_extension/super_admin.rb +25 -0
  101. data/lib/rhino/resource/active_record_extension.rb +32 -0
  102. data/lib/rhino/resource/active_record_tree.rb +50 -0
  103. data/lib/rhino/resource/active_storage_extension.rb +41 -0
  104. data/lib/rhino/resource/describe.rb +19 -0
  105. data/lib/rhino/resource/owner.rb +172 -0
  106. data/lib/rhino/resource/params.rb +31 -0
  107. data/lib/rhino/resource/properties.rb +192 -0
  108. data/lib/rhino/resource/reference.rb +29 -0
  109. data/lib/rhino/resource/routing.rb +107 -0
  110. data/lib/rhino/resource/serialization.rb +13 -0
  111. data/lib/rhino/resource/sieves.rb +36 -0
  112. data/lib/rhino/resource.rb +55 -0
  113. data/lib/rhino/sieve/filter.rb +149 -0
  114. data/lib/rhino/sieve/geospatial.rb +45 -0
  115. data/lib/rhino/sieve/helpers.rb +11 -0
  116. data/lib/rhino/sieve/limit.rb +20 -0
  117. data/lib/rhino/sieve/offset.rb +16 -0
  118. data/lib/rhino/sieve/order.rb +143 -0
  119. data/lib/rhino/sieve/search.rb +20 -0
  120. data/lib/rhino/sieve.rb +159 -0
  121. data/lib/rhino/test_case/controller.rb +145 -0
  122. data/lib/rhino/test_case/model.rb +86 -0
  123. data/lib/rhino/test_case/override.rb +19 -0
  124. data/lib/rhino/test_case/policy.rb +76 -0
  125. data/lib/rhino/test_case.rb +11 -0
  126. data/lib/rhino/version.rb +17 -0
  127. data/lib/rhino_project_core.rb +131 -0
  128. data/lib/tasks/rhino.rake +24 -0
  129. data/lib/tasks/rhino_dev.rake +17 -0
  130. data/lib/validators/country_validator.rb +11 -0
  131. data/lib/validators/email_validator.rb +8 -0
  132. data/lib/validators/ipv4_validator.rb +10 -0
  133. data/lib/validators/mac_address_validator.rb +9 -0
  134. metadata +531 -0
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "properties_describe"
4
+
5
+ module Rhino
6
+ module Resource
7
+ module ActiveRecordExtension
8
+ module Properties
9
+ extend ActiveSupport::Concern
10
+
11
+ include Rhino::Resource::ActiveRecordExtension::PropertiesDescribe
12
+
13
+ class_methods do # rubocop:disable Metrics/BlockLength
14
+ def identifier_property
15
+ primary_key
16
+ end
17
+
18
+ def readable_properties
19
+ props = attribute_names - foreign_key_properties
20
+
21
+ props.concat(reference_properties)
22
+
23
+ props.map(&:to_s)
24
+ end
25
+
26
+ def creatable_properties
27
+ writeable_properties
28
+ end
29
+
30
+ def updatable_properties
31
+ # https://api.rubyonrails.org/classes/ActiveRecord/ReadonlyAttributes/ClassMethods.html#method-i-readonly_attributes
32
+ writeable_properties - readonly_attributes.to_a
33
+ end
34
+
35
+ private
36
+ # FIXME: Duplicated in params.rb
37
+ def reference_to_sym(reference)
38
+ reference.is_a?(Hash) ? reference.keys.first : reference
39
+ end
40
+
41
+ # FIXME: Include counter caches as well
42
+ def automatic_properties
43
+ [identifier_property] + send(:all_timestamp_attributes_in_model)
44
+ end
45
+
46
+ def virtual_properties
47
+ columns.select(&:virtual?).map(&:name) # rubocop:todo Performance/SelectMap
48
+ end
49
+
50
+ def foreign_key_properties
51
+ reflect_on_all_associations(:belongs_to).map(&:foreign_key).map(&:to_s)
52
+ end
53
+
54
+ # rubocop:todo Style/OptionalBooleanParameter
55
+ def reference_properties(read = true)
56
+ references.filter_map do |r|
57
+ sym = reference_to_sym(r)
58
+
59
+ # All references are readable
60
+ next sym if read
61
+
62
+ # Writeable if a one type or accepting nested
63
+ association = reflect_on_association(sym)
64
+ # rubocop:todo Performance/CollectionLiteralInLoop, Layout/LineLength
65
+ if %i[has_one belongs_to].include?(association.macro) || nested_attributes_options.key?(sym) || association.class_name == "ActiveStorage::Attachment"
66
+ sym
67
+ end
68
+ # rubocop:enable Performance/CollectionLiteralInLoop, Layout/LineLength
69
+ end
70
+ end
71
+ # rubocop:enable Style/OptionalBooleanParameter
72
+
73
+ def writeable_properties
74
+ # Direct properties for this model
75
+ props = attribute_names - automatic_properties - virtual_properties - foreign_key_properties
76
+
77
+ props.concat(reference_properties(false))
78
+
79
+ props.map(&:to_s)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,228 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "js_regex"
4
+
5
+ module Rhino
6
+ module Resource
7
+ module ActiveRecordExtension
8
+ module PropertiesDescribe # rubocop:disable Metrics/ModuleLength
9
+ extend ActiveSupport::Concern
10
+
11
+ class_methods do # rubocop:disable Metrics/BlockLength
12
+ def describe_property(property) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
13
+ name = property_name(property).to_s
14
+ raise StandardError, "#{name} is not a valid property" unless property?(name)
15
+
16
+ {
17
+ "x-rhino-attribute": {
18
+ name:,
19
+ readableName: name.titleize,
20
+ readable: read_properties.include?(property),
21
+ creatable: create_properties.include?(property),
22
+ updatable: update_properties.include?(property)
23
+ },
24
+ readOnly: property_read_only?(name),
25
+ writeOnly: property_write_only?(name),
26
+ nullable: property_nullable?(name),
27
+ default: property_default(name)
28
+ }
29
+ .merge(property_type_and_format(property))
30
+ .merge(property_validations(property))
31
+ .deep_merge(property_overrides(property))
32
+ .compact
33
+ end
34
+
35
+ private
36
+ # FIXME: It can be a hash if passed in from a reference which might have something like
37
+ # rhino_references %i[{blog_posts: [:comments]}]
38
+ # but I cannot find current spot where it is used like that currently
39
+ def property_name(property)
40
+ property.is_a?(Hash) ? property.keys.first : property
41
+ end
42
+
43
+ def ref_descriptor(names)
44
+ {
45
+ type: :reference,
46
+ anyOf: names.map { |name| { :$ref => "#/components/schemas/#{name.singularize}" } }
47
+ }
48
+ end
49
+
50
+ def property_type_and_format_attr(name) # rubocop:todo Metrics/MethodLength
51
+ atype = attribute_types[name.to_s].type
52
+
53
+ # The PG array delegates type to "subtype" which is the actual type of the array elements
54
+ if attribute_types[name.to_s].is_a? ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array
55
+ return {
56
+ type: :array,
57
+ items: {
58
+ type: atype
59
+ }
60
+ }
61
+ end
62
+
63
+ if %i[datetime date time].include?(atype)
64
+ return {
65
+ type: 'string',
66
+ format: atype
67
+ }
68
+ end
69
+
70
+ { type: atype }
71
+ end
72
+
73
+ def nested_array_options(name)
74
+ ref_sym = name.to_sym
75
+
76
+ array_options = {}
77
+
78
+ if nested_attributes_options[ref_sym]
79
+ array_options[:creatable] = true
80
+ array_options[:updatable] = true
81
+ array_options[:destroyable] = nested_attributes_options[ref_sym][:allow_destroy]
82
+ end
83
+
84
+ { "x-rhino-attribute-array": array_options.merge(_properties_array[ref_sym] || {}) }
85
+ end
86
+
87
+ # rubocop:todo Metrics/PerceivedComplexity
88
+ # rubocop:todo Metrics/AbcSize
89
+ def property_type_and_format_ref(name) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
90
+ assoc = reflections[name]
91
+ klasses = if assoc.options[:polymorphic]
92
+ assoc.active_record.send("#{assoc.name}_types").map(&:constantize).map { |m| m.model_name.singular }
93
+ else
94
+ # FIXME: The tr hack is to match how model_name in rails handles modularized classes
95
+ [assoc.options[:class_name]&.underscore&.tr('/', '_') || name]
96
+ end
97
+
98
+ return ref_descriptor(klasses) unless reflections[name].macro == :has_many
99
+
100
+ {
101
+ type: :array,
102
+ items: ref_descriptor(klasses).merge(nested_array_options(name))
103
+ }
104
+ end
105
+ # rubocop:enable Metrics/AbcSize
106
+ # rubocop:enable Metrics/PerceivedComplexity
107
+
108
+ def property_type_and_format(name) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
109
+ # Special cases
110
+ return { type: :identifier } if name == identifier_property
111
+ return { type: :string } if defined_enums.key?(name)
112
+
113
+ # FIXME: Hack for tags for now
114
+ if attribute_types.key?(name.to_s) && attribute_types[name.to_s].class.to_s == 'ActsAsTaggableOn::Taggable::TagListType'
115
+ return {
116
+ type: :array,
117
+ items: {
118
+ type: 'string'
119
+ }
120
+ }
121
+ end
122
+
123
+ # Use the attribute type if possible
124
+ return property_type_and_format_attr(name) if attribute_types.key?(name.to_s)
125
+
126
+ return property_type_and_format_ref(name) if reflections.key?(name)
127
+
128
+ # FIXME: There may be no way to reach this
129
+ # raise UnknownpropertyType
130
+ { type: :unknown }
131
+ end
132
+
133
+ def property_overrides(property)
134
+ return {} unless _properties_overrides.key?(property)
135
+
136
+ _properties_overrides[property].deep_symbolize_keys
137
+ end
138
+
139
+ def property_validations(property) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
140
+ constraint_hash = {}
141
+
142
+ # https://swagger.io/specification/
143
+
144
+ validators_on(property).each do |v|
145
+ if v.is_a? ActiveModel::Validations::NumericalityValidator
146
+ if v.options.key?(:greater_than)
147
+ constraint_hash[:minimum] = v.options[:greater_than]
148
+ constraint_hash[:exclusiveMinimum] = true
149
+ end
150
+
151
+ if v.options.key?(:less_than)
152
+ constraint_hash[:maximum] = v.options[:less_than]
153
+ constraint_hash[:exclusiveMaximum] = true
154
+ end
155
+
156
+ constraint_hash[:minimum] = v.options[:greater_than_or_equal_to] if v.options.key?(:greater_than_or_equal_to)
157
+ constraint_hash[:maximum] = v.options[:less_than_or_equal_to] if v.options.key?(:less_than_or_equal_to)
158
+
159
+ if v.options.key?(:in)
160
+ constraint_hash[:minimum] = v.options[:in].min
161
+ constraint_hash[:maximum] = v.options[:in].max
162
+ end
163
+ end
164
+
165
+ if v.is_a? ::ActiveRecord::Validations::LengthValidator
166
+ constraint_hash[:minLength] = v.options[:minimum] || v.options[:is]
167
+ constraint_hash[:maxLength] = v.options[:maximum] || v.options[:is]
168
+ end
169
+
170
+ constraint_hash[:pattern] = JsRegex.new(v.options[:with]).source if v.is_a? ::ActiveModel::Validations::FormatValidator
171
+
172
+ constraint_hash[:enum] = v.options[:in] if v.is_a? ActiveModel::Validations::InclusionValidator
173
+ end
174
+
175
+ constraint_hash[:enum] = defined_enums[property].keys if defined_enums.key?(property)
176
+
177
+ constraint_hash.compact
178
+ end
179
+
180
+ # If there is a presence validator in the model it is not nullable.
181
+ # if there is no optional: true on an association, rails will add a
182
+ # presence validator automatically
183
+ # Otherwise check the db for the actual column or foreign key setting
184
+ # Return nil instead of false for compaction
185
+ def property_nullable?(name) # rubocop:todo Metrics/AbcSize
186
+ # Check for any presence validator
187
+ return false if validators_on(name).any?(::ActiveRecord::Validations::PresenceValidator)
188
+
189
+ # https://guides.rubyonrails.org/active_record_validations.html#numericality
190
+ # By default, numericality doesn't allow nil values. You can use allow_nil: true option to permit it.
191
+ validators_on(name).select { |v| v.is_a? ::ActiveRecord::Validations::NumericalityValidator }.each do |v|
192
+ return false unless v.options[:allow_nil]
193
+ end
194
+
195
+ name = reflections[name].foreign_key if reflections.key?(name)
196
+
197
+ # Check the column null setting
198
+ return columns_hash[name].null if columns_hash.key?(name)
199
+
200
+ true
201
+ end
202
+
203
+ # Return nil instead of false for compaction
204
+ def property_read_only?(name)
205
+ return unless read_properties.include?(name) && (create_properties.exclude?(name) && update_properties.exclude?(name))
206
+
207
+ true
208
+ end
209
+
210
+ # Return nil instead of false for compaction
211
+ def property_write_only?(name)
212
+ return unless (create_properties.include?(name) || update_properties.include?(name)) && read_properties.exclude?(name)
213
+
214
+ true
215
+ end
216
+
217
+ def property_default(name)
218
+ # FIXME: This will not handle datetime fields
219
+ # https://github.com/rails/rails/issues/27077 sets the default in the db
220
+ # but Blog.new does not set the default value like other attributes
221
+ # https://nubinary.atlassian.net/browse/NUB-298
222
+ _default_attributes[name].type_cast(_default_attributes[name].value_before_type_cast)
223
+ end
224
+ end
225
+ end
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module Resource
5
+ module ActiveRecordExtension
6
+ module Reference
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ scope :eager_load_refs, -> { includes(klass.references) } if defined?(scope)
11
+
12
+ def references_for_serialization
13
+ serialize_references(references)
14
+ end
15
+
16
+ private
17
+ # FIXME: Duplicated in params.rb
18
+ def reference_to_sym(reference)
19
+ reference.is_a?(Hash) ? reference.keys.first : reference
20
+ end
21
+
22
+ # FIXME: Duplicated in params.rb
23
+ def reference_from_sym(sym)
24
+ ref = try(sym)
25
+ return unless ref
26
+
27
+ # This is mostly how serializable_hash does it
28
+ # Get the first object
29
+ return ref.first if ref.respond_to?(:to_ary)
30
+
31
+ ref
32
+ end
33
+
34
+ def serialize_references(references)
35
+ hash = {}
36
+ references.each do |ref_item|
37
+ sym = reference_to_sym(ref_item)
38
+
39
+ hash[sym] = {}
40
+ hash[sym][:methods] = :display_name
41
+ hash[sym][:include] = serialize_references(ref_item[sym]) if ref_item.is_a?(Hash)
42
+ end.flatten.compact
43
+
44
+ hash
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module Resource
5
+ module ActiveRecordExtension
6
+ module Routing
7
+ extend ActiveSupport::Concern
8
+
9
+ class_methods do
10
+ def route_key
11
+ if route_singular?
12
+ model_name.singular_route_key
13
+ else
14
+ model_name.route_key
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module Resource
5
+ module ActiveRecordExtension
6
+ module Search
7
+ extend ActiveSupport::Concern
8
+
9
+ class_methods do
10
+ def rhino_search(fields, associated_fields = {})
11
+ include PgSearch::Model
12
+ # stores the searchable fields so it is possible to retrieve them
13
+ # in the open API model description
14
+ @rhino_is_searchable = fields.present? || associated_fields.present?
15
+ # FIXME: We can't autodiscover text fields because it causes a very
16
+ # slow reload in the development server with bigger apps
17
+ pg_search_scope :search_text_fields, against: fields, associated_against: associated_fields, using: { tsearch: { prefix: true } }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module Resource
5
+ module ActiveRecordExtension
6
+ module Serialization
7
+ extend ActiveSupport::Concern
8
+
9
+ def to_caching_json
10
+ serializable_hash(methods: :display_name, include: references_for_serialization)
11
+ # JSON.generate(hash)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module Resource
5
+ module ActiveRecordExtension
6
+ module SuperAdmin
7
+ extend ActiveSupport::Concern
8
+
9
+ class_methods do
10
+ def ransackable_attributes(_auth_object = nil)
11
+ authorizable_ransackable_attributes & read_properties
12
+ end
13
+
14
+ def ransackable_associations(_auth_object = nil)
15
+ authorizable_ransackable_associations & references.map(&:to_s)
16
+ end
17
+
18
+ def ransackable_filters(auth_object = nil)
19
+ ransackable_attributes(auth_object) + ransackable_associations
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../resource'
4
+ require_relative 'active_record_extension/properties'
5
+ require_relative 'active_record_extension/reference'
6
+ require_relative 'active_record_extension/describe'
7
+ require_relative 'active_record_extension/routing'
8
+ require_relative 'active_record_extension/params'
9
+ require_relative 'active_record_extension/serialization'
10
+ require_relative 'active_record_extension/search'
11
+ require_relative 'active_record_extension/super_admin'
12
+
13
+ module Rhino
14
+ module Resource
15
+ module ActiveRecordExtension
16
+ extend ActiveSupport::Concern
17
+
18
+ # Base
19
+ include Rhino::Resource
20
+
21
+ # Active Record implementations
22
+ include Rhino::Resource::ActiveRecordExtension::Properties
23
+ include Rhino::Resource::ActiveRecordExtension::Reference
24
+ include Rhino::Resource::ActiveRecordExtension::Describe
25
+ include Rhino::Resource::ActiveRecordExtension::Routing
26
+ include Rhino::Resource::ActiveRecordExtension::Params
27
+ include Rhino::Resource::ActiveRecordExtension::Serialization
28
+ include Rhino::Resource::ActiveRecordExtension::Search
29
+ include Rhino::Resource::ActiveRecordExtension::SuperAdmin
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module Resource
5
+ module ActiveRecordTree
6
+ extend ActiveSupport::Concern
7
+
8
+ # Base
9
+ include Rhino::Resource::ActiveRecordExtension unless Rhino.auto_include_active_record
10
+
11
+ included do
12
+ has_ancestry
13
+ end
14
+
15
+ class_methods do
16
+ def readable_properties
17
+ super + ["children"]
18
+ end
19
+
20
+ def describe_property(property)
21
+ return super unless property == "children"
22
+
23
+ super.deep_merge({ type: :array, items: ref_descriptor([model_name.element]) })
24
+ end
25
+
26
+ # FIXME: Need to recurse to a MAX DEPTH
27
+ def readable_params(type, refs = references)
28
+ # Remove the base children property and replace with hash
29
+ base_show = super - ["children"]
30
+ base_show + [children: [base_show]]
31
+ end
32
+
33
+ # FIXME: Need writeable params override
34
+ end
35
+
36
+ def serializable_hash(options = nil)
37
+ super(options).merge(children: arrange_serializable_with_options(options))
38
+ end
39
+
40
+ private
41
+ # We do this to carry things like methods all the way through the
42
+ # serialization
43
+ def arrange_serializable_with_options(options = nil)
44
+ children.arrange_serializable do |parent, _children|
45
+ parent.serializable_hash(options)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module Resource
5
+ module ActiveStorageExtension
6
+ extend ActiveSupport::Concern
7
+
8
+ # Base
9
+ include Rhino::Resource::ActiveRecordExtension unless Rhino.auto_include_active_record
10
+
11
+ included do
12
+ attribute :url
13
+ attribute :url_attachment
14
+
15
+ rhino_policy :active_storage_attachment
16
+
17
+ def url
18
+ Rails.application.routes.url_helpers.rails_blob_url(self, only_path: false)
19
+ end
20
+
21
+ def url_attachment
22
+ Rails.application.routes.url_helpers.rails_blob_url(self, only_path: false, disposition: :attachment)
23
+ end
24
+
25
+ def display_name
26
+ filename.to_s
27
+ end
28
+ end
29
+
30
+ class_methods do
31
+ def readable_properties
32
+ super + ["signed_id"]
33
+ end
34
+ end
35
+
36
+ def serializable_hash(options = nil)
37
+ super(options).merge("signed_id" => signed_id)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rhino
4
+ module Resource
5
+ module Describe
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ delegate :describe, to: :class
10
+ end
11
+
12
+ class_methods do
13
+ def describe
14
+ raise NotImplementedError, '#describe is not implemented'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end