wallaby 4.1.6

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.
Files changed (209) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +29 -0
  4. data/app/assets/javascripts/wallaby/application.js +15 -0
  5. data/app/assets/javascripts/wallaby/form.js +8 -0
  6. data/app/assets/stylesheets/wallaby/application.scss +51 -0
  7. data/app/assets/stylesheets/wallaby/base/_functions.scss +0 -0
  8. data/app/assets/stylesheets/wallaby/base/_layout.scss +14 -0
  9. data/app/assets/stylesheets/wallaby/base/_mixins.scss +0 -0
  10. data/app/assets/stylesheets/wallaby/base/_normalize.scss +0 -0
  11. data/app/assets/stylesheets/wallaby/base/_reset.scss +0 -0
  12. data/app/assets/stylesheets/wallaby/base/_vars.scss +5 -0
  13. data/app/assets/stylesheets/wallaby/components/_forms.scss +53 -0
  14. data/app/assets/stylesheets/wallaby/components/_nav.scss +19 -0
  15. data/app/assets/stylesheets/wallaby/components/_pagination.scss +105 -0
  16. data/app/assets/stylesheets/wallaby/components/_tables.scss +78 -0
  17. data/app/assets/stylesheets/wallaby/components/_text.scss +11 -0
  18. data/app/assets/stylesheets/wallaby/form.scss +11 -0
  19. data/app/assets/stylesheets/wallaby/summernote.scss.erb +7 -0
  20. data/app/controllers/wallaby/application_controller.rb +21 -0
  21. data/app/controllers/wallaby/core_controller.rb +28 -0
  22. data/app/controllers/wallaby/resources_controller.rb +134 -0
  23. data/app/controllers/wallaby/secure_controller.rb +42 -0
  24. data/app/routes/wallaby/resources_router.rb +52 -0
  25. data/app/security/ability.rb +33 -0
  26. data/app/views/layouts/wallaby/_footer.html.erb +2 -0
  27. data/app/views/layouts/wallaby/_header.html.erb +57 -0
  28. data/app/views/layouts/wallaby/_navs.html.erb +1 -0
  29. data/app/views/layouts/wallaby/application.html.erb +22 -0
  30. data/app/views/layouts/wallaby/error.html.erb +20 -0
  31. data/app/views/wallaby/core/home.html.erb +5 -0
  32. data/app/views/wallaby/errors/access_denied.html.erb +1 -0
  33. data/app/views/wallaby/errors/not_authenticated.html.erb +1 -0
  34. data/app/views/wallaby/errors/not_found.html.erb +6 -0
  35. data/app/views/wallaby/errors/unprocessable_entity.erb +1 -0
  36. data/app/views/wallaby/resources/_form.html.erb +12 -0
  37. data/app/views/wallaby/resources/_index_actions.html.erb +1 -0
  38. data/app/views/wallaby/resources/_resource_actions.html.erb +3 -0
  39. data/app/views/wallaby/resources/edit.html.erb +14 -0
  40. data/app/views/wallaby/resources/form/_belongs_to.html.erb +21 -0
  41. data/app/views/wallaby/resources/form/_bigint.html.erb +9 -0
  42. data/app/views/wallaby/resources/form/_binary.html.erb +12 -0
  43. data/app/views/wallaby/resources/form/_bit.html.erb +9 -0
  44. data/app/views/wallaby/resources/form/_bit_varying.html.erb +9 -0
  45. data/app/views/wallaby/resources/form/_boolean.html.erb +14 -0
  46. data/app/views/wallaby/resources/form/_cidr.html.erb +9 -0
  47. data/app/views/wallaby/resources/form/_citext.html.erb +21 -0
  48. data/app/views/wallaby/resources/form/_color.html.erb +20 -0
  49. data/app/views/wallaby/resources/form/_date.html.erb +29 -0
  50. data/app/views/wallaby/resources/form/_daterange.html.erb +37 -0
  51. data/app/views/wallaby/resources/form/_datetime.html.erb +30 -0
  52. data/app/views/wallaby/resources/form/_decimal.html.erb +9 -0
  53. data/app/views/wallaby/resources/form/_email.html.erb +5 -0
  54. data/app/views/wallaby/resources/form/_float.html.erb +9 -0
  55. data/app/views/wallaby/resources/form/_has_and_belongs_to_many.html.erb +13 -0
  56. data/app/views/wallaby/resources/form/_has_many.html.erb +13 -0
  57. data/app/views/wallaby/resources/form/_has_one.html.erb +7 -0
  58. data/app/views/wallaby/resources/form/_hstore.html.erb +25 -0
  59. data/app/views/wallaby/resources/form/_inet.html.erb +9 -0
  60. data/app/views/wallaby/resources/form/_int4range.html.erb +18 -0
  61. data/app/views/wallaby/resources/form/_int8range.html.erb +18 -0
  62. data/app/views/wallaby/resources/form/_integer.html.erb +9 -0
  63. data/app/views/wallaby/resources/form/_json.html.erb +23 -0
  64. data/app/views/wallaby/resources/form/_jsonb.html.erb +23 -0
  65. data/app/views/wallaby/resources/form/_ltree.html.erb +5 -0
  66. data/app/views/wallaby/resources/form/_macaddr.html.erb +9 -0
  67. data/app/views/wallaby/resources/form/_money.html.erb +12 -0
  68. data/app/views/wallaby/resources/form/_numrange.html.erb +18 -0
  69. data/app/views/wallaby/resources/form/_password.html.erb +5 -0
  70. data/app/views/wallaby/resources/form/_point.html.erb +18 -0
  71. data/app/views/wallaby/resources/form/_string.html.erb +5 -0
  72. data/app/views/wallaby/resources/form/_text.html.erb +21 -0
  73. data/app/views/wallaby/resources/form/_time.html.erb +29 -0
  74. data/app/views/wallaby/resources/form/_tsrange.html.erb +38 -0
  75. data/app/views/wallaby/resources/form/_tstzrange.html.erb +38 -0
  76. data/app/views/wallaby/resources/form/_tsvector.html.erb +5 -0
  77. data/app/views/wallaby/resources/form/_uuid.html.erb +9 -0
  78. data/app/views/wallaby/resources/form/_xml.html.erb +23 -0
  79. data/app/views/wallaby/resources/index/_belongs_to.html.erb +1 -0
  80. data/app/views/wallaby/resources/index/_bigint.html.erb +1 -0
  81. data/app/views/wallaby/resources/index/_binary.html.erb +1 -0
  82. data/app/views/wallaby/resources/index/_bit.html.erb +5 -0
  83. data/app/views/wallaby/resources/index/_bit_varying.html.erb +5 -0
  84. data/app/views/wallaby/resources/index/_boolean.html.erb +5 -0
  85. data/app/views/wallaby/resources/index/_cidr.html.erb +6 -0
  86. data/app/views/wallaby/resources/index/_citext.html.erb +12 -0
  87. data/app/views/wallaby/resources/index/_color.html.erb +5 -0
  88. data/app/views/wallaby/resources/index/_date.html.erb +7 -0
  89. data/app/views/wallaby/resources/index/_daterange.html.erb +8 -0
  90. data/app/views/wallaby/resources/index/_datetime.html.erb +7 -0
  91. data/app/views/wallaby/resources/index/_decimal.html.erb +1 -0
  92. data/app/views/wallaby/resources/index/_email.html.erb +1 -0
  93. data/app/views/wallaby/resources/index/_float.html.erb +1 -0
  94. data/app/views/wallaby/resources/index/_has_and_belongs_to_many.html.erb +11 -0
  95. data/app/views/wallaby/resources/index/_has_many.html.erb +11 -0
  96. data/app/views/wallaby/resources/index/_has_one.html.erb +1 -0
  97. data/app/views/wallaby/resources/index/_hstore.html.erb +12 -0
  98. data/app/views/wallaby/resources/index/_inet.html.erb +6 -0
  99. data/app/views/wallaby/resources/index/_int4range.html.erb +7 -0
  100. data/app/views/wallaby/resources/index/_int8range.html.erb +7 -0
  101. data/app/views/wallaby/resources/index/_integer.html.erb +1 -0
  102. data/app/views/wallaby/resources/index/_json.html.erb +12 -0
  103. data/app/views/wallaby/resources/index/_jsonb.html.erb +12 -0
  104. data/app/views/wallaby/resources/index/_ltree.html.erb +12 -0
  105. data/app/views/wallaby/resources/index/_macaddr.html.erb +5 -0
  106. data/app/views/wallaby/resources/index/_money.html.erb +1 -0
  107. data/app/views/wallaby/resources/index/_numrange.html.erb +7 -0
  108. data/app/views/wallaby/resources/index/_point.html.erb +6 -0
  109. data/app/views/wallaby/resources/index/_string.html.erb +12 -0
  110. data/app/views/wallaby/resources/index/_text.html.erb +12 -0
  111. data/app/views/wallaby/resources/index/_time.html.erb +6 -0
  112. data/app/views/wallaby/resources/index/_tsrange.html.erb +8 -0
  113. data/app/views/wallaby/resources/index/_tstzrange.html.erb +8 -0
  114. data/app/views/wallaby/resources/index/_tsvector.html.erb +12 -0
  115. data/app/views/wallaby/resources/index/_uuid.html.erb +12 -0
  116. data/app/views/wallaby/resources/index/_xml.html.erb +12 -0
  117. data/app/views/wallaby/resources/index.html.erb +66 -0
  118. data/app/views/wallaby/resources/new.html.erb +14 -0
  119. data/app/views/wallaby/resources/shared/_resource_nav.html.erb +29 -0
  120. data/app/views/wallaby/resources/show/_belongs_to.html.erb +7 -0
  121. data/app/views/wallaby/resources/show/_bigint.html.erb +1 -0
  122. data/app/views/wallaby/resources/show/_binary.html.erb +1 -0
  123. data/app/views/wallaby/resources/show/_bit.html.erb +5 -0
  124. data/app/views/wallaby/resources/show/_bit_varying.html.erb +5 -0
  125. data/app/views/wallaby/resources/show/_boolean.html.erb +5 -0
  126. data/app/views/wallaby/resources/show/_cidr.html.erb +6 -0
  127. data/app/views/wallaby/resources/show/_citext.html.erb +1 -0
  128. data/app/views/wallaby/resources/show/_color.html.erb +5 -0
  129. data/app/views/wallaby/resources/show/_date.html.erb +7 -0
  130. data/app/views/wallaby/resources/show/_daterange.html.erb +7 -0
  131. data/app/views/wallaby/resources/show/_datetime.html.erb +6 -0
  132. data/app/views/wallaby/resources/show/_decimal.html.erb +1 -0
  133. data/app/views/wallaby/resources/show/_email.html.erb +1 -0
  134. data/app/views/wallaby/resources/show/_float.html.erb +1 -0
  135. data/app/views/wallaby/resources/show/_has_and_belongs_to_many.html.erb +5 -0
  136. data/app/views/wallaby/resources/show/_has_many.html.erb +5 -0
  137. data/app/views/wallaby/resources/show/_has_one.html.erb +1 -0
  138. data/app/views/wallaby/resources/show/_hstore.html.erb +5 -0
  139. data/app/views/wallaby/resources/show/_inet.html.erb +6 -0
  140. data/app/views/wallaby/resources/show/_int4range.html.erb +7 -0
  141. data/app/views/wallaby/resources/show/_int8range.html.erb +7 -0
  142. data/app/views/wallaby/resources/show/_integer.html.erb +1 -0
  143. data/app/views/wallaby/resources/show/_json.html.erb +5 -0
  144. data/app/views/wallaby/resources/show/_jsonb.html.erb +5 -0
  145. data/app/views/wallaby/resources/show/_ltree.html.erb +1 -0
  146. data/app/views/wallaby/resources/show/_macaddr.html.erb +5 -0
  147. data/app/views/wallaby/resources/show/_money.html.erb +1 -0
  148. data/app/views/wallaby/resources/show/_numrange.html.erb +7 -0
  149. data/app/views/wallaby/resources/show/_point.html.erb +6 -0
  150. data/app/views/wallaby/resources/show/_string.html.erb +1 -0
  151. data/app/views/wallaby/resources/show/_text.html.erb +1 -0
  152. data/app/views/wallaby/resources/show/_time.html.erb +6 -0
  153. data/app/views/wallaby/resources/show/_tsrange.html.erb +7 -0
  154. data/app/views/wallaby/resources/show/_tstzrange.html.erb +7 -0
  155. data/app/views/wallaby/resources/show/_tsvector.html.erb +1 -0
  156. data/app/views/wallaby/resources/show/_uuid.html.erb +5 -0
  157. data/app/views/wallaby/resources/show/_xml.html.erb +5 -0
  158. data/app/views/wallaby/resources/show.html.erb +31 -0
  159. data/app/views/wallaby/shared/_flash_messages.html.erb +13 -0
  160. data/config/locales/en.yml +29 -0
  161. data/config/routes.rb +34 -0
  162. data/lib/adaptors/wallaby/active_record/model_decorator/fields_builder.rb +105 -0
  163. data/lib/adaptors/wallaby/active_record/model_decorator/title_field_finder.rb +18 -0
  164. data/lib/adaptors/wallaby/active_record/model_decorator.rb +81 -0
  165. data/lib/adaptors/wallaby/active_record/model_finder.rb +12 -0
  166. data/lib/adaptors/wallaby/active_record/model_operator/normalizer.rb +44 -0
  167. data/lib/adaptors/wallaby/active_record/model_operator/permitter.rb +50 -0
  168. data/lib/adaptors/wallaby/active_record/model_operator/querier.rb +47 -0
  169. data/lib/adaptors/wallaby/active_record/model_operator/validator.rb +16 -0
  170. data/lib/adaptors/wallaby/active_record/model_operator.rb +82 -0
  171. data/lib/adaptors/wallaby/active_record.rb +2 -0
  172. data/lib/decorators/wallaby/resource_decorator.rb +78 -0
  173. data/lib/errors/wallaby/deprecated.rb +4 -0
  174. data/lib/errors/wallaby/general_error.rb +4 -0
  175. data/lib/errors/wallaby/invalid_error.rb +4 -0
  176. data/lib/errors/wallaby/model_not_found.rb +4 -0
  177. data/lib/errors/wallaby/not_authenticated.rb +4 -0
  178. data/lib/errors/wallaby/not_implemented.rb +4 -0
  179. data/lib/errors/wallaby/operation_not_found.rb +4 -0
  180. data/lib/errors/wallaby/resource_not_found.rb +4 -0
  181. data/lib/forms/wallaby/form_builder.rb +30 -0
  182. data/lib/handlers/wallaby/cached_compiled_erb.rb +14 -0
  183. data/lib/helpers/wallaby/application_helper.rb +30 -0
  184. data/lib/helpers/wallaby/core_helper.rb +50 -0
  185. data/lib/helpers/wallaby/form_helper.rb +21 -0
  186. data/lib/helpers/wallaby/links_helper.rb +83 -0
  187. data/lib/helpers/wallaby/paginatable_helper.rb +9 -0
  188. data/lib/helpers/wallaby/resources_helper.rb +55 -0
  189. data/lib/helpers/wallaby/secure_helper.rb +25 -0
  190. data/lib/helpers/wallaby/sorting_helper.rb +43 -0
  191. data/lib/helpers/wallaby/styling_helper.rb +57 -0
  192. data/lib/interfaces/wallaby/mode.rb +18 -0
  193. data/lib/interfaces/wallaby/model_decorator.rb +58 -0
  194. data/lib/interfaces/wallaby/model_finder.rb +5 -0
  195. data/lib/interfaces/wallaby/model_operator.rb +31 -0
  196. data/lib/services/wallaby/decorator_finder.rb +16 -0
  197. data/lib/services/wallaby/lookup_context_wrapper.rb +40 -0
  198. data/lib/services/wallaby/map.rb +53 -0
  199. data/lib/services/wallaby/model_servicer.rb +38 -0
  200. data/lib/services/wallaby/servicer_finder.rb +5 -0
  201. data/lib/tasks/wallaby_tasks.rake +4 -0
  202. data/lib/utils/wallaby/utils.rb +31 -0
  203. data/lib/wallaby/configuration/models.rb +17 -0
  204. data/lib/wallaby/configuration/security.rb +30 -0
  205. data/lib/wallaby/configuration.rb +49 -0
  206. data/lib/wallaby/engine.rb +89 -0
  207. data/lib/wallaby/version.rb +3 -0
  208. data/lib/wallaby.rb +5 -0
  209. metadata +459 -0
@@ -0,0 +1,81 @@
1
+ class Wallaby::ActiveRecord::ModelDecorator < Wallaby::ModelDecorator
2
+ def fields
3
+ @fields ||= {}.tap do |hash|
4
+ if model_class.table_exists?
5
+ hash.merge! general_fields
6
+ hash.merge! association_fields
7
+ hash.except! *foreign_keys_from_associations
8
+ end
9
+ end.with_indifferent_access
10
+ end
11
+
12
+ def index_fields
13
+ @index_fields ||= fields.deep_dup
14
+ end
15
+
16
+ def show_fields
17
+ @show_fields ||= fields.deep_dup
18
+ end
19
+
20
+ def form_fields
21
+ @form_fields ||= fields.deep_dup
22
+ end
23
+
24
+ def index_field_names
25
+ @index_field_names ||= index_fields.reject do |field_name, metadata|
26
+ metadata[:is_association] ||
27
+ %w( binary citext hstore json jsonb text tsvector xml ).include?(metadata[:type])
28
+ end.keys
29
+ end
30
+
31
+ def form_field_names
32
+ @form_field_names ||= form_fields.reject do |field_name, metadata|
33
+ %W( #{ primary_key } updated_at created_at ).include?(field_name) ||
34
+ metadata[:has_scope] ||
35
+ metadata[:is_through]
36
+ end.keys
37
+ end
38
+
39
+ def form_active_errors(resource)
40
+ resource.errors
41
+ end
42
+
43
+ def primary_key
44
+ @model_class.primary_key
45
+ end
46
+
47
+ def guess_title(resource)
48
+ resource.public_send title_field_finder.find
49
+ end
50
+
51
+ protected
52
+ def field_builder
53
+ @field_builder ||= Wallaby::ActiveRecord::ModelDecorator::FieldsBuilder.new @model_class
54
+ end
55
+
56
+ def title_field_finder
57
+ @title_field_finder ||= Wallaby::ActiveRecord::ModelDecorator::TitleFieldFinder.new @model_class, general_fields
58
+ end
59
+
60
+ delegate :general_fields, :association_fields, to: :field_builder
61
+
62
+ def foreign_keys_from_associations(associations = association_fields)
63
+ associations.inject([]) do |keys, (field_name, metadata)|
64
+ keys << metadata[:foreign_key] if metadata[:foreign_key]
65
+ keys << metadata[:polymorphic_type] if metadata[:polymorphic_type]
66
+ keys
67
+ end
68
+ end
69
+
70
+ def many_associations(associations = association_fields)
71
+ associations.select do |field_name, metadata|
72
+ /many/ =~ metadata[:type] && !metadata[:is_through]
73
+ end
74
+ end
75
+
76
+ def belongs_to_associations(associations = association_fields)
77
+ associations.select do |field_name, metadata|
78
+ 'belongs_to' == metadata[:type]
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,12 @@
1
+ class Wallaby::ActiveRecord::ModelFinder < Wallaby::ModelFinder
2
+ def all
3
+ Rails.cache.fetch 'wallaby/active_record/model_finder' do
4
+ ActiveRecord::Base.subclasses.reject do |model_class|
5
+ model_class.abstract_class? ||
6
+ model_class.to_s.start_with?('#<') ||
7
+ model_class.name == 'ActiveRecord::SchemaMigration' ||
8
+ model_class.name.index('HABTM')
9
+ end.sort_by &:to_s
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,44 @@
1
+ class Wallaby::ActiveRecord::ModelOperator::Normalizer
2
+ def initialize(model_decorator)
3
+ @model_decorator = model_decorator
4
+ end
5
+
6
+ def normalize(params)
7
+ params.each do |field_name, values|
8
+ next unless metadata = @model_decorator.fields[field_name]
9
+
10
+ case metadata[:type]
11
+ when /range/
12
+ normalize_range_values params, field_name, values
13
+ when /point/
14
+ normalize_point_values params, field_name, values
15
+ when /binary/
16
+ normalize_binary_values params, field_name, values
17
+ end
18
+ end
19
+ end
20
+
21
+ def normalize_range_values(params, field_name, values)
22
+ normalized = Array(values).map(&:presence).compact
23
+ if normalized.length > 0 && values.length == 2
24
+ params[field_name] = values.first...values.last
25
+ else
26
+ params[field_name] = nil
27
+ end
28
+ end
29
+
30
+ def normalize_point_values(params, field_name, values)
31
+ normalized = Array(values).map(&:presence).compact
32
+ if normalized.length > 0
33
+ params[field_name] = values.map &:to_f
34
+ else
35
+ params[field_name] = nil
36
+ end
37
+ end
38
+
39
+ def normalize_binary_values(params, field_name, values)
40
+ if values.is_a?(ActionDispatch::Http::UploadedFile)
41
+ params[field_name] = values.read
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,50 @@
1
+ class Wallaby::ActiveRecord::ModelOperator::Permitter
2
+ def initialize(model_decorator)
3
+ @model_decorator = model_decorator
4
+ end
5
+
6
+ def simple_field_names
7
+ field_names = non_range_fields.keys + belongs_to_fields.map do |_, metadata|
8
+ [ metadata[:foreign_key], metadata[:polymorphic_type] ]
9
+ end.flatten.compact
10
+ field_names.reject do |field_name|
11
+ [ @model_decorator.primary_key, 'created_at', 'updated_at' ].include? field_name
12
+ end
13
+ end
14
+
15
+ def compound_hashed_fields
16
+ field_names = range_fields.keys + many_association_fields.map{ |_, metadata| metadata[:foreign_key] }
17
+ Wallaby::Utils.to_hash(field_names.map{ |field_name| [ field_name, [] ] })
18
+ end
19
+
20
+ protected
21
+ def non_association_fields
22
+ @model_decorator.fields.select{ |_, metadata| !metadata[:is_association] }
23
+ end
24
+
25
+ def non_range_fields
26
+ non_association_fields.select{ |_, metadata| !(/range|point/ =~ metadata[:type]) }
27
+ end
28
+
29
+ def range_fields
30
+ non_association_fields.select do |_, metadata|
31
+ /range|point/ =~ metadata[:type]
32
+ end
33
+ end
34
+
35
+ def association_fields
36
+ @model_decorator.fields.select do |_, metadata|
37
+ metadata[:is_association] && !metadata[:has_scope] && !metadata[:is_through]
38
+ end
39
+ end
40
+
41
+ def many_association_fields
42
+ association_fields.select{ |_, metadata| /many/ =~ metadata[:type] }
43
+ end
44
+
45
+ def belongs_to_fields
46
+ association_fields.select do |field_name, metadata|
47
+ 'belongs_to' == metadata[:type]
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,47 @@
1
+ class Wallaby::ActiveRecord::ModelOperator::Querier
2
+ def initialize(model_decorator)
3
+ @model_decorator = model_decorator
4
+ @model_class = @model_decorator.model_class
5
+ end
6
+
7
+ def search(params)
8
+ text_keywords, field_keywords = extract params
9
+ query = @model_class.where nil
10
+ query = text_search text_keywords, query
11
+ query = field_search field_keywords, query
12
+ query
13
+ end
14
+
15
+ protected
16
+ def extract(params)
17
+ all_keywords = (params[:q] || '').split(' ').compact
18
+ field_keywords = all_keywords.select{ |v| v.split(':').length == 2 }
19
+ [ all_keywords - field_keywords, field_keywords ]
20
+ end
21
+
22
+ def text_search(keywords, query)
23
+ return query if keywords.blank?
24
+
25
+ queries = text_fields.inject([]) do |queries, field_name|
26
+ likes = keywords.map do |keyword|
27
+ [ "UPPER(#{ field_name }) LIKE ?", "%#{ keyword.upcase }%" ]
28
+ end
29
+ queries << [ "(#{ likes.map(&:first).join ' AND ' })", likes.map(&:last) ]
30
+ end
31
+ query.where queries.map(&:first).join(' OR '), *queries.map(&:last).flatten
32
+ end
33
+
34
+ def field_search(keywords, query)
35
+ return query if keywords.blank?
36
+
37
+ hashed_queries = Wallaby::Utils.to_hash(keywords.map{ |v| v.split ':' })
38
+ query.where hashed_queries
39
+ end
40
+
41
+ def text_fields
42
+ @model_decorator.fields.select do |field_name, metadata|
43
+ @model_decorator.index_field_names.include?(field_name) &&
44
+ %w( string text citext ).include?(metadata[:type])
45
+ end.keys
46
+ end
47
+ end
@@ -0,0 +1,16 @@
1
+ class Wallaby::ActiveRecord::ModelOperator::Validator
2
+ def initialize(model_decorator)
3
+ @model_decorator = model_decorator
4
+ end
5
+
6
+ def valid?(resource)
7
+ resource.attributes.each do |field_name, values|
8
+ next unless metadata = @model_decorator.fields[field_name]
9
+ if %w( daterange tsrange tstzrange ).include?(metadata[:type]) &&
10
+ values.try(:any?, &:blank?)
11
+ resource.errors.add field_name, 'required for range data'
12
+ end
13
+ end
14
+ resource.errors.blank?
15
+ end
16
+ end
@@ -0,0 +1,82 @@
1
+ class Wallaby::ActiveRecord::ModelOperator < Wallaby::ModelOperator
2
+ def collection(params, ability)
3
+ query = querier.search params
4
+ query = query.order params[:sort] if params[:sort].present?
5
+ query.accessible_by ability
6
+ end
7
+
8
+ def new(params)
9
+ permitted = permit params rescue {}
10
+ @model_class.new permitted
11
+ end
12
+
13
+ def find(id, params)
14
+ @model_class.find id
15
+ rescue ActiveRecord::RecordNotFound
16
+ fail Wallaby::ResourceNotFound
17
+ end
18
+
19
+ def create(params, ability)
20
+ resource = @model_class.new
21
+ resource.assign_attributes normalize permit(params)
22
+ ensure_attributes_for ability, :create, resource
23
+ resource.save if valid? resource
24
+ [ resource, resource.errors.blank? ]
25
+ rescue ActiveRecord::StatementInvalid => e
26
+ resource.errors.add :base, e.message
27
+ [ resource, false ]
28
+ end
29
+
30
+ def update(resource, params, ability)
31
+ resource.assign_attributes normalize permit(params)
32
+ ensure_attributes_for ability, :update, resource
33
+ resource.save if valid? resource
34
+ [ resource, resource.errors.blank? ]
35
+ rescue ActiveRecord::StatementInvalid => e
36
+ resource.errors.add :base, e.message
37
+ [ resource, false ]
38
+ end
39
+
40
+ def destroy(resource, params)
41
+ resource.destroy
42
+ end
43
+
44
+ protected
45
+ def permit(params)
46
+ params.require(param_key).permit(permitter.simple_field_names << permitter.compound_hashed_fields)
47
+ end
48
+
49
+ def normalize(params)
50
+ normalizer.normalize params
51
+ end
52
+
53
+ def valid?(resource)
54
+ validator.valid? resource
55
+ end
56
+
57
+ def ensure_attributes_for(ability, action, resource)
58
+ return if ability.blank?
59
+ restricted_conditions = ability.attributes_for action, resource
60
+ resource.assign_attributes restricted_conditions
61
+ end
62
+
63
+ def param_key
64
+ @model_class.model_name.param_key
65
+ end
66
+
67
+ def permitter
68
+ @permitter ||= Wallaby::ActiveRecord::ModelOperator::Permitter.new @model_decorator
69
+ end
70
+
71
+ def querier
72
+ @querier ||= Wallaby::ActiveRecord::ModelOperator::Querier.new @model_decorator
73
+ end
74
+
75
+ def normalizer
76
+ @normalizer ||= Wallaby::ActiveRecord::ModelOperator::Normalizer.new @model_decorator
77
+ end
78
+
79
+ def validator
80
+ @validator ||= Wallaby::ActiveRecord::ModelOperator::Validator.new @model_decorator
81
+ end
82
+ end
@@ -0,0 +1,2 @@
1
+ class Wallaby::ActiveRecord < Wallaby::Mode
2
+ end
@@ -0,0 +1,78 @@
1
+ class Wallaby::ResourceDecorator
2
+ class << self
3
+ def model_class
4
+ if self < Wallaby::ResourceDecorator
5
+ @model_class ||= Wallaby::Utils.to_model_class name.gsub('Decorator', ''), name
6
+ end
7
+ end
8
+
9
+ def model_decorator
10
+ if self < Wallaby::ResourceDecorator
11
+ @model_decorator ||= Wallaby::DecoratorFinder.new_model model_class
12
+ end
13
+ end
14
+
15
+ def decorate(resource)
16
+ return resource if resource.is_a? Wallaby::ResourceDecorator
17
+ new resource
18
+ end
19
+
20
+ delegate *begin
21
+ Wallaby::ModelDecorator.instance_methods \
22
+ - Object.instance_methods - %i( model_class )
23
+ end, to: :model_decorator, allow_nil: true
24
+ end
25
+
26
+ def initialize(resource)
27
+ @resource = resource
28
+ @model_decorator = self.class.model_decorator || Wallaby::DecoratorFinder.new_model(model_class)
29
+ end
30
+
31
+ def method_missing(method_id, *args)
32
+ if @resource.respond_to? method_id
33
+ @resource.public_send method_id, *args
34
+ else
35
+ super
36
+ end
37
+ end
38
+
39
+ delegate :to_s, :to_param, :to_params, to: :@resource
40
+ delegate *begin
41
+ Wallaby::ModelDecorator.instance_methods \
42
+ - %i( index_fields index_field_names show_fields show_field_names form_fields form_field_names ) \
43
+ - Object.instance_methods
44
+ end, to: :@model_decorator
45
+ attr_reader :model_decorator
46
+
47
+ def model_class
48
+ @resource.class
49
+ end
50
+
51
+ def resource
52
+ @resource
53
+ end
54
+
55
+ def to_label
56
+ @model_decorator.guess_title(@resource) || primary_key_value
57
+ end
58
+
59
+ def errors
60
+ @model_decorator.form_active_errors(@resource)
61
+ end
62
+
63
+ def primary_key_value
64
+ @resource.public_send primary_key
65
+ end
66
+
67
+ [ '', 'index_', 'show_', 'form_' ].each do |prefix|
68
+ class_eval <<-RUBY
69
+ def #{ prefix }fields
70
+ @#{ prefix }fields ||= @model_decorator.#{ prefix }fields.dup.freeze
71
+ end
72
+
73
+ def #{ prefix }field_names
74
+ @#{ prefix }field_names ||= @model_decorator.#{ prefix }field_names.dup.freeze
75
+ end
76
+ RUBY
77
+ end
78
+ end
@@ -0,0 +1,4 @@
1
+ module Wallaby
2
+ class Deprecated < GeneralError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Wallaby
2
+ class GeneralError < ::StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Wallaby
2
+ class InvalidError < ::StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Wallaby
2
+ class ModelNotFound < GeneralError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Wallaby
2
+ class NotAuthenticated < GeneralError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Wallaby
2
+ class NotImplemented < GeneralError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Wallaby
2
+ class OperationNotFound < GeneralError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Wallaby
2
+ class ResourceNotFound < GeneralError
3
+ end
4
+ end
@@ -0,0 +1,30 @@
1
+ class Wallaby::FormBuilder < ActionView::Helpers::FormBuilder
2
+ def error_class(field_name)
3
+ 'has-error' if has_error? field_name
4
+ end
5
+
6
+ def error_messages(field_name)
7
+ errors = Array object.errors[ field_name ]
8
+ return if errors.blank?
9
+
10
+ content_tag :ul, class: 'text-danger' do
11
+ errors.each do |message|
12
+ concat content_tag :li, content_tag(:small, raw(message))
13
+ end
14
+ end
15
+ end
16
+
17
+ protected
18
+ def method_missing(method, *args, &block)
19
+ if @template.respond_to? method
20
+ self.class.delegate method, to: :@template
21
+ @template.public_send method, *args, &block
22
+ else
23
+ super
24
+ end
25
+ end
26
+
27
+ def has_error?(field_name)
28
+ object.errors[field_name].present?
29
+ end
30
+ end
@@ -0,0 +1,14 @@
1
+ require 'erubis'
2
+
3
+ # TODO: move this kind of logic into a gem called faster rails :)
4
+ class Wallaby::CachedCompiledErb < ActionView::Template::Handlers::ERB
5
+ def call(template)
6
+ if Rails.env.development?
7
+ super
8
+ else
9
+ Rails.cache.fetch "wallaby/views/erb/#{ template.inspect }" do
10
+ super
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ module Wallaby::ApplicationHelper
2
+ def clean_params
3
+ params.except :resources, :action
4
+ end
5
+
6
+ # override `actionview/lib/action_view/routing_url_for.rb#url_for`
7
+ def url_for(options = nil)
8
+ if options.is_a?(Hash) && options.slice(:action, :resources).length == 2
9
+ return wallaby_resourceful_url_for options
10
+ end
11
+ super
12
+ end
13
+
14
+ def wallaby_resourceful_url_for(options = {})
15
+ # DEPRECATION WARNING: You are calling a `*_path` helper with the `only_path` option explicitly set to `false`. This option will stop working on path helpers in Rails 5. Use the corresponding `*_url` helper instead.
16
+ options = options.except :only_path
17
+ case options[:action]
18
+ when 'index', 'create'
19
+ wallaby_engine.resources_path options
20
+ when 'new'
21
+ wallaby_engine.new_resource_path options
22
+ when 'edit'
23
+ wallaby_engine.edit_resource_path options
24
+ when 'show', 'update', 'destroy'
25
+ wallaby_engine.resource_path options
26
+ else
27
+ wallaby_engine.url_for options
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,50 @@
1
+ require 'securerandom'
2
+
3
+ # NOTE: Global helper methods should go in here
4
+ module Wallaby::CoreHelper
5
+ include Wallaby::StylingHelper
6
+ include Wallaby::LinksHelper
7
+
8
+ def to_model_label(model_class)
9
+ Wallaby::Utils.to_model_label model_class
10
+ end
11
+
12
+ def to_resources_name(model_class)
13
+ Wallaby::Utils.to_resources_name model_class
14
+ end
15
+
16
+ def current_model_label
17
+ if current_resources_name.present?
18
+ label = to_model_label current_resources_name
19
+ return "Resource: #{ label }" if label.present?
20
+ end
21
+ 'Resources'
22
+ end
23
+
24
+ def body_class
25
+ [
26
+ params[:action],
27
+ current_resources_name.try(:gsub, '::', '__'),
28
+ content_for(:custom_body_class)
29
+ ].compact.join ' '
30
+ end
31
+
32
+ def page_title
33
+ 'Wallaby::Admin'
34
+ end
35
+
36
+ def ct(key, options = {})
37
+ t key, { raise: true }.merge(options)
38
+ rescue I18n::MissingTranslationData => e
39
+ keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope])
40
+ keys.last.to_s.titleize
41
+ end
42
+
43
+ def random_uuid
44
+ SecureRandom.uuid
45
+ end
46
+
47
+ def model_classes
48
+ Wallaby::Map.model_classes.sort_by &:name
49
+ end
50
+ end
@@ -0,0 +1,21 @@
1
+ module Wallaby::FormHelper
2
+ def form_type_partial_render(options = {}, locals = {}, &block)
3
+ form = locals[:form]
4
+ field_name = locals[:field_name].to_s
5
+
6
+ fail ArgumentError unless form.present? && field_name.present? && form.object.is_a?(Wallaby::ResourceDecorator)
7
+
8
+ locals[:object] = object = form.object
9
+ locals[:metadata] = object.form_metadata_of locals[:field_name]
10
+ locals[:value] = object.public_send locals[:field_name]
11
+
12
+ render(options, locals, &block) or render('string', locals, &block)
13
+ end
14
+
15
+ def model_choices(model_decorator)
16
+ collection = model_servicer(model_decorator).collection Hash.new, current_ability
17
+ decorate(collection).map do |decorated|
18
+ [ decorated.to_label, decorated.primary_key_value ]
19
+ end
20
+ end
21
+ end