wallaby 4.1.6

Sign up to get free protection for your applications and to get access to all the features.
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