drg_cms 0.6.0.1 → 0.6.1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/drg_cms/drg_cms.js +454 -145
  3. data/app/assets/javascripts/drg_cms_application.js +1 -1
  4. data/app/assets/stylesheets/drg_cms/drg_cms.css +635 -244
  5. data/app/assets/stylesheets/drg_cms/select-multiple.css +18 -12
  6. data/app/assets/stylesheets/drg_cms_cms.css +1 -1
  7. data/app/controllers/cmsedit_controller.rb +515 -335
  8. data/app/controllers/dc_application_controller.rb +378 -111
  9. data/app/controllers/dc_common_controller.rb +105 -14
  10. data/app/{controllers → controls}/browse_models_control.rb +0 -0
  11. data/app/controls/dc_help_control.rb +126 -0
  12. data/app/{controllers → controls}/dc_page_control.rb +24 -8
  13. data/app/controls/dc_poll_result_control.rb +88 -0
  14. data/app/controls/dc_report.rb +223 -0
  15. data/app/{controllers → controls}/design_element_settings_control.rb +0 -0
  16. data/app/forms/all_options.yml +44 -9
  17. data/app/forms/cms_menu.yml +28 -18
  18. data/app/forms/dc_ad.yml +11 -22
  19. data/app/forms/dc_big_table.yml +1 -0
  20. data/app/forms/dc_big_table_value.yml +1 -0
  21. data/app/forms/dc_category.yml +2 -1
  22. data/app/forms/dc_design.yml +20 -16
  23. data/app/forms/dc_filter.yml +3 -6
  24. data/app/forms/dc_help_1.yml +109 -0
  25. data/app/forms/dc_journal.yml +3 -1
  26. data/app/forms/dc_json_ld.yml +59 -0
  27. data/app/forms/dc_key_value.yml +32 -0
  28. data/app/forms/dc_link.yml +1 -1
  29. data/app/forms/dc_menu.yml +2 -0
  30. data/app/forms/dc_menu_item.yml +2 -0
  31. data/app/forms/dc_page.yml +3 -5
  32. data/app/forms/dc_part.yml +1 -0
  33. data/app/forms/dc_piece.yml +1 -0
  34. data/app/forms/dc_poll.yml +15 -5
  35. data/app/forms/dc_poll_item.yml +2 -1
  36. data/app/forms/dc_poll_result.yml +83 -0
  37. data/app/forms/dc_poll_result_export.yml +35 -0
  38. data/app/forms/dc_seo.yml +33 -0
  39. data/app/forms/dc_simple_menu.yml +2 -0
  40. data/app/forms/dc_site.yml +4 -12
  41. data/app/forms/dc_user.yml +27 -11
  42. data/app/forms/dc_user_role.yml +3 -0
  43. data/app/forms/json_ld_schema.yml +168 -0
  44. data/app/helpers/cms_common_helper.rb +375 -0
  45. data/app/helpers/cms_edit_helper.rb +506 -0
  46. data/app/helpers/cms_helper.rb +268 -0
  47. data/app/helpers/cms_index_helper.rb +580 -0
  48. data/app/helpers/dc_application_helper.rb +218 -306
  49. data/app/models/concerns/dc_page_concern.rb +40 -6
  50. data/app/models/concerns/dc_policy_rule_concern.rb +20 -8
  51. data/app/models/concerns/dc_seo_concern.rb +66 -0
  52. data/app/models/concerns/dc_site_concern.rb +67 -44
  53. data/app/models/concerns/dc_user_concern.rb +57 -18
  54. data/app/models/dc_design.rb +30 -18
  55. data/app/models/dc_filter.rb +22 -13
  56. data/app/models/dc_json_ld.rb +152 -0
  57. data/app/models/dc_key_value.rb +48 -0
  58. data/app/models/dc_key_value_store.rb +1 -0
  59. data/app/models/dc_memory.rb +8 -1
  60. data/app/models/dc_page.rb +0 -1
  61. data/app/models/dc_permission.rb +49 -9
  62. data/app/models/dc_policy.rb +25 -14
  63. data/app/models/dc_policy_role.rb +22 -11
  64. data/app/models/dc_poll.rb +39 -19
  65. data/app/models/dc_poll_result.rb +46 -0
  66. data/app/models/dc_temp.rb +140 -0
  67. data/app/models/dc_user_role.rb +2 -2
  68. data/app/models/drgcms_form_fields.rb +12 -1
  69. data/app/models/drgcms_form_fields/action.rb +61 -0
  70. data/app/models/drgcms_form_fields/comment.rb +8 -4
  71. data/app/models/drgcms_form_fields/date_picker.rb +11 -9
  72. data/app/models/drgcms_form_fields/date_select.rb +1 -1
  73. data/app/models/drgcms_form_fields/datetime_picker.rb +12 -10
  74. data/app/models/drgcms_form_fields/datetime_select.rb +1 -1
  75. data/app/models/drgcms_form_fields/drgcms_field.rb +55 -9
  76. data/app/models/drgcms_form_fields/embedded.rb +26 -16
  77. data/app/models/drgcms_form_fields/file_field.rb +52 -0
  78. data/app/models/drgcms_form_fields/file_select.rb +2 -2
  79. data/app/models/drgcms_form_fields/hash_field.rb +90 -0
  80. data/app/models/drgcms_form_fields/hidden_field.rb +1 -1
  81. data/app/models/drgcms_form_fields/html_field.rb +1 -1
  82. data/app/models/drgcms_form_fields/link_to.rb +2 -2
  83. data/app/models/drgcms_form_fields/method.rb +66 -0
  84. data/app/models/drgcms_form_fields/multitext_autocomplete.rb +23 -14
  85. data/app/models/drgcms_form_fields/number_field.rb +15 -6
  86. data/app/models/drgcms_form_fields/radio.rb +96 -0
  87. data/app/models/drgcms_form_fields/readonly.rb +2 -2
  88. data/app/models/drgcms_form_fields/select.rb +92 -29
  89. data/app/models/drgcms_form_fields/text_area.rb +1 -1
  90. data/app/models/drgcms_form_fields/text_autocomplete.rb +31 -17
  91. data/app/models/drgcms_form_fields/text_field.rb +1 -1
  92. data/app/models/drgcms_form_fields/text_with_select.rb +6 -3
  93. data/app/models/drgcms_form_fields/tree_select.rb +15 -4
  94. data/app/{helpers → renderers}/dc_ad_renderer.rb +0 -0
  95. data/app/{helpers → renderers}/dc_big_menu_renderer.rb +1 -0
  96. data/app/{helpers → renderers}/dc_captcha_renderer.rb +0 -0
  97. data/app/{helpers → renderers}/dc_common_renderer.rb +0 -0
  98. data/app/{helpers → renderers}/dc_gallery_renderer.rb +1 -0
  99. data/app/{helpers → renderers}/dc_menu_renderer.rb +11 -4
  100. data/app/{helpers → renderers}/dc_page_renderer.rb +1 -0
  101. data/app/{helpers → renderers}/dc_part_renderer.rb +5 -4
  102. data/app/{helpers → renderers}/dc_piece_renderer.rb +1 -1
  103. data/app/{helpers → renderers}/dc_poll_renderer.rb +91 -64
  104. data/app/{helpers → renderers}/dc_renderer.rb +1 -0
  105. data/app/{helpers → renderers}/dc_simple_menu_renderer.rb +1 -0
  106. data/app/views/cmsedit/{remove_edit_stuff.js.erb → __remove_edit_stuff.js.erb} +0 -0
  107. data/app/views/cmsedit/{show.html.erb → __show.html.erb} +0 -0
  108. data/app/views/cmsedit/_edit_stuff.html.erb +4 -25
  109. data/app/views/cmsedit/_form.html.erb +4 -3
  110. data/app/views/cmsedit/_result.html.erb +2 -3
  111. data/app/views/cmsedit/edit.html.erb +4 -1
  112. data/app/views/cmsedit/index.html.erb +7 -1
  113. data/app/views/cmsedit/new.html.erb +3 -1
  114. data/app/views/dc_common/_help.html.erb +17 -0
  115. data/app/views/layouts/models.html.erb +2 -1
  116. data/config/locales/drgcms_en.yml +27 -3
  117. data/config/locales/drgcms_sl.yml +32 -5
  118. data/config/locales/models_en.yml +65 -17
  119. data/config/locales/models_sl.yml +69 -18
  120. data/drg_cms.gemspec +1 -1
  121. data/lib/drg_cms.rb +61 -1
  122. data/lib/drg_cms/version.rb +1 -1
  123. data/lib/generators/new_drg_form/new_drg_form_generator.rb +9 -2
  124. data/lib/tasks/database.rake +6 -56
  125. metadata +73 -54
  126. data/app/assets/stylesheets/drg_cms/__jquery-ui.css +0 -339
  127. data/app/helpers/application_helper.rb +0 -2
  128. data/app/helpers/cmsedit_helper.rb +0 -888
  129. data/app/models/dc_dummy.rb +0 -102
  130. data/test/fixtures/drg_cms_test_data.rb +0 -87
@@ -28,10 +28,10 @@
28
28
  -ms-transition: border linear 0.2s, box-shadow linear 0.2s;
29
29
  -o-transition: border linear 0.2s, box-shadow linear 0.2s;
30
30
  transition: border linear 0.2s, box-shadow linear 0.2s;
31
- border: 2px solid #ddd;
32
- -webkit-border-radius: 3px;
33
- -moz-border-radius: 3px;
34
- border-radius: 3px;
31
+ border: 1px dashed #888;
32
+ -webkit-border-radius: 1px;
33
+ -moz-border-radius: 1px;
34
+ border-radius: 1px;
35
35
  position: relative;
36
36
  height: 200px;
37
37
  padding: 0;
@@ -39,12 +39,9 @@
39
39
  }
40
40
 
41
41
  .ms-container .ms-list.ms-focus{
42
- border-color: rgba(82, 168, 236, 0.8);
43
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
44
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
45
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
46
- outline: 0;
47
- outline: thin dotted \9;
42
+ border: 1px solid rgba(76,154,255, 1);
43
+ outline: 1px solid rgba(76,154,255, 1);
44
+ border-radius: 1px;
48
45
  }
49
46
 
50
47
  .ms-container ul{
@@ -65,12 +62,15 @@
65
62
  }
66
63
 
67
64
  .ms-container .ms-selectable li.ms-elem-selectable{
68
- border-bottom: 1px #eee solid;
69
65
  padding: 2px 10px;
70
- color: #555;
66
+ color: #444;
71
67
  font-size: 14px;
72
68
  }
73
69
 
70
+ .ms-container .ms-selectable li:nth-child(odd) {
71
+ background-color: #f4f4f4;
72
+ }
73
+
74
74
  .ms-container .ms-selectable li.ms-hover{
75
75
  cursor: pointer;
76
76
  color: #fff;
@@ -88,6 +88,12 @@
88
88
  display: none;
89
89
  }
90
90
 
91
+
92
+ .ms-container .ms-selected {
93
+ font-weight: 600;
94
+ }
95
+
91
96
  .pull-right.ms-elem-selected{
92
97
  float: right;
98
+ font-size: smaller;
93
99
  }
@@ -19,4 +19,4 @@
19
19
  */
20
20
 
21
21
  /* Required for link buttons to look alike */
22
- .dc-link a, .dc-link-submit input {font-weight: bold; font-size: 12px; }
22
+ .dc-link a, .dc-link-submit input {font-weight: 600; }
@@ -1,4 +1,3 @@
1
- #coding: utf-8
2
1
  #--
3
2
  # Copyright (c) 2012+ Damjan Rems
4
3
  #
@@ -76,211 +75,20 @@
76
75
  # If filter method returns false user will be presented with flash error.
77
76
  ########################################################################
78
77
  class CmseditController < DcApplicationController
79
- before_action :check_authorization, :except => [:login, :logout, :test]
78
+ before_action :check_authorization, :except => [:login, :logout, :test, :run]
80
79
  before_action :dc_reload_patches if Rails.env.development?
80
+ protect_from_forgery with: :null_session, only: Proc.new { |c| c.request.format.json? }
81
81
 
82
82
  layout 'cms'
83
83
 
84
84
  ########################################################################
85
- # Will check and set sorting options for current result set. Subroutine of index method.
86
- ########################################################################
87
- def check_sort_options() #:nodoc:
88
- table_name = @tables.first[1]
89
- old_sort = session[table_name][:sort].to_s
90
- sort, direction = old_sort.split(' ')
91
- # sort is requested
92
- if params['sort']
93
- # reverse sort if same selected
94
- if params['sort'] == sort
95
- direction = (direction == '1') ? '-1' : '1'
96
- end
97
- direction ||= 1
98
- sort = params[:sort]
99
- session[table_name][:sort] = "#{params['sort']} #{direction}"
100
- session[table_name][:page] = 1
101
- end
102
- @records.sort( sort => direction.to_i ) if session[table_name][:sort]
103
- params['sort'] = nil # otherwise there is problem with other links
104
- end
105
-
106
- ########################################################################
107
- # Set aditional filter options when filter is defined by filter method in control object.
108
- ########################################################################
109
- def user_filter_options(model) #:nodoc:
110
- table_name = @tables.first[1]
111
- if session[table_name]
112
- DcFilter.get_filter(session[table_name][:filter]) || model
113
- else
114
- model
115
- end
116
- end
117
-
118
- ########################################################################
119
- # Will set session[table_name][:filter] and save last filter settings to session.
120
- # subroutine of check_filter_options.
121
- ########################################################################
122
- def set_session_filter(table_name)
123
- if params[:filter] == 'off' # clear all values
124
- session[table_name][:filter] = nil
125
- return
126
- end
127
-
128
- filter_value = if params[:filter_value].nil?
129
- # NIL indicates that no filtering is needed
130
- '#NIL'
131
- else
132
- if params[:filter_value].class == String and params[:filter_value][0] == '@'
133
- # Internal value. Remove leading @ and evaluate expression
134
- expression = DcInternals.get(params[:filter_value])
135
- eval(expression) rescue nil
136
- else
137
- # No filter when empty
138
- params[:filter_value] == '' ? '#NIL' : params[:filter_value]
139
- end
140
- end
141
- # if filter field parameter is omitted then just set filter value
142
- session[table_name][:filter] =
143
- if params[:filter_field].nil?
144
- saved = YAML.load(session[table_name][:filter])
145
- saved['value'] = filter_value
146
- saved.to_yaml
147
- else
148
- # As field defined. Split name and alternative input field
149
- field = if params[:filter_field].match(' as ')
150
- params[:filter_input] = params[:filter_field].split(' as ').last.strip
151
- params[:filter_field].split(' as ').first.strip
152
- else
153
- params[:filter_field]
154
- end
155
- #
156
- {'field' => field,
157
- 'operation' => params[:filter_oper],
158
- 'value' => filter_value,
159
- 'input' => params[:filter_input],
160
- 'table' => table_name }.to_yaml
161
- end
162
- # must be. Otherwise kaminari includes parameter on paging
163
- params[:filter] = nil
164
- params[:filter_id] = nil
165
- params[:filter_oper] = nil
166
- params[:filter_input] = nil
167
- params[:filter_field] = nil
168
- end
169
-
170
- ########################################################################
171
- # Will check and set current filter options for result set. Subroutine of index method.
172
- ########################################################################
173
- def check_filter_options() #:nodoc:
174
- table_name = @tables.first[1]
175
- model = @tables.first[0]
176
- session[table_name] ||= {}
177
- # process page
178
- session[table_name][:page] = params[:page] if params[:page]
179
- # new filter is applied
180
- if params[:filter]
181
- set_session_filter(table_name)
182
- session[table_name][:page] = 1
183
- end
184
- # if data model has field dc_site_id ensure that only documents which belong to the site are selected.
185
- site_id = dc_get_site._id if dc_get_site
186
- # dont't filter site if no dc_site_id field or user is ADMIN
187
- site_id = nil if !model.method_defined?('dc_site_id') or dc_user_can(DcPermission::CAN_ADMIN)
188
- site_id = nil if session[table_name][:filter].to_s.match('dc_site_id')
189
- #
190
- if @records = DcFilter.get_filter(session[table_name][:filter])
191
- @records = @records.and(dc_site_id: site_id) if site_id
192
- else
193
- @records = if site_id
194
- model.where(dc_site_id: site_id)
195
- else
196
- model
197
- end
198
- end
199
- =begin
200
- # TODO Use only fields requested. Higly experimental but necessary in some scenarios
201
- if (columns = @form['result_set']['columns'])
202
- cols = []
203
- columns.each { |k,v| cols << v['name'] }
204
- p '*',cols,'*'
205
- @records = @records.only(cols)
206
- end
207
- =end
208
- # pagination if required
209
- per_page = (@form['result_set']['per_page'] || 30).to_i
210
- @records = @records.page(session[table_name][:page]).per(per_page) if per_page > 0
211
- end
212
-
213
- ########################################################################
214
- # Process index action for normal collections.
215
- ########################################################################
216
- def process_collections #:nodoc
217
- # If result_set is not defined on form, then it will fail. :return_to should know where to go
218
- if @form['result_set'].nil?
219
- process_return_to(params[:return_to] || 'reload')
220
- return true
221
- end
222
- # for now enable only filtering of top level documents
223
- if @tables.size == 1
224
- check_filter_options()
225
- check_sort_options()
226
- end
227
- # result set is defined by filter method in control object
228
- if @form['result_set']['filter']
229
- if respond_to?(@form['result_set']['filter'])
230
- @records = send @form['result_set']['filter']
231
- # something iz wrong. flash[] should have explanation.
232
- if @records.class == FalseClass
233
- @records = []
234
- render(action: :index)
235
- return true
236
- end
237
- # pagination but only if not already set
238
- unless (@form['table'] == 'dc_memory' or @records.options[:limit])
239
- per_page = (@form['result_set']['per_page'] || 30).to_i
240
- @records = @records.page(params[:page]).per(per_page) if per_page > 0
241
- end
242
- else
243
- Rails.logger.error "Error: result_set:filter: #{@form['result_set']['filter']} not found in controls!"
244
- end
245
- else
246
- if @tables.size > 1
247
- rec = @tables.first[0].find(@ids.first) # top most document.id
248
- 1.upto(@tables.size - 2) { |i| rec = rec.send(@tables[i][1].pluralize).find(@ids[i]) } # find embedded childrens by ids
249
- @records = rec.send(@tables.last[1].pluralize) # current embedded set
250
- # sort by order if order field is present in model
251
- if @tables.last[1].classify.constantize.respond_to?(:order)
252
- @records = @records.order_by('order asc')
253
- end
254
- end
255
- end
256
- false
257
- end
258
-
259
- ########################################################################
260
- # Process index action for in memory data.
261
- ########################################################################
262
- def process_in_memory #:nodoc
263
- @records = []
264
- # result set is defined by filter method in control object
265
- if (method = @form['result_set']['filter'])
266
- send(method) if respond_to?(method)
267
- end
268
- # result set is defined by class method
269
- if (klass_method = @form['result_set']['filter_method'])
270
- _klass, method = klass_method.split('.')
271
- klass = _klass.classify.constantize
272
- @records = klass.send(method) if klass.respond_to?(method)
273
- end
274
- false
275
- end
276
-
277
- ########################################################################
278
- # Indx action
85
+ # Index action
279
86
  ########################################################################
280
87
  def index
88
+ @form['result_set'] ||= {}
281
89
  redirected = (@form['table'] == 'dc_memory' ? process_in_memory : process_collections)
282
90
  return if redirected
283
- #
91
+
284
92
  call_callback_method(@form['result_set']['footer'] || 'dc_footer')
285
93
  respond_to do |format|
286
94
  format.html { render action: :index }
@@ -300,9 +108,9 @@ end
300
108
  ########################################################################
301
109
  def show
302
110
  find_record
111
+ # before_show callback
303
112
  if (m = callback_method('before_show') )
304
113
  ret = call_callback_method(m)
305
- # Don't do anything if return is false
306
114
  if ret.class == FalseClass
307
115
  @form['readonly'] = nil # must be
308
116
  return index
@@ -321,7 +129,7 @@ end
321
129
  ########################################################################
322
130
  def login
323
131
  if params[:id] == 'test' then set_test_site
324
- elsif params[:ok] then redirect_to '/'
132
+ elsif params[:ok] then render action: 'login', layout: 'cms'
325
133
  else
326
134
  session[:edit_mode] = 0
327
135
  render action: 'login', layout: 'cms'
@@ -340,20 +148,21 @@ def logout
340
148
  end
341
149
 
342
150
  ########################################################################
343
- # Logout action. Used to logout direct from CMS.
344
- #
345
- # Logout can be called directly with url http://site.com/cmsedit/logout
151
+ # Shortcut for setting currently selected site in development. Will search
152
+ # for dc_site document with site name 'test' and set alias_for to site
153
+ # url parameter.
346
154
  ########################################################################
347
155
  def set_test_site
348
156
  # only in development
349
- return dc_render_404 if !Rails.env.development?
157
+ return dc_render_404 unless Rails.env.development?
158
+
350
159
  alias_site = DcSite.find_by(:name => params[:site])
351
160
  return dc_render_404 unless alias_site
161
+
352
162
  # update alias for
353
- site = DcSite.find_by(:name => 'test')
163
+ site = DcSite.find_by(:name => 'test')
354
164
  site.alias_for = params[:site]
355
165
  site.save
356
- # redirect to root
357
166
  redirect_to '/'
358
167
  end
359
168
 
@@ -361,17 +170,17 @@ end
361
170
  # New action.
362
171
  ########################################################################
363
172
  def new
364
- # clear flash messages.
173
+ # clear flash messages.
365
174
  flash[:error] = flash[:warning] = flash[:info] = nil
366
175
  create_new_empty_record
176
+ # before_new callback
367
177
  if (m = callback_method('before_new') )
368
178
  ret = call_callback_method(m)
369
- # Don't do anything if return is false
370
179
  return index if ret.class == FalseClass
371
180
  end
372
181
  table = @tables.last[1] + '.'
373
- # initial values set on page
374
- if cookies[:record] and cookies[:record].size > 0
182
+ # initial values set on page
183
+ if cookies[:record] && cookies[:record].size > 0
375
184
  Marshal.load(cookies[:record]).each do |k,v|
376
185
  k = k.to_s
377
186
  if k.match(table)
@@ -380,63 +189,71 @@ def new
380
189
  end
381
190
  end
382
191
  end
383
- # initial values set in url
192
+ # initial values set in url (params)
384
193
  params.each do |k,v|
385
194
  if k.match(table)
386
195
  field = k.split('.').last
387
196
  @record.send("#{field}=", v) if @record.respond_to?(field)
388
197
  end
389
198
  end
390
- # This is how we set default values for new record
391
- dc_new_record() if respond_to?('dc_new_record')
199
+ # new_record callback. Set default values for new record
200
+ if (m = callback_method('new_record') ) then call_callback_method(m) end
392
201
  @parms['action'] = 'create'
393
202
  end
394
203
 
395
204
  ########################################################################
396
205
  # Duplicate embedded document. Since embedded documents are returned differently
397
206
  # then top level document. Subroutine of duplicate_socument.
207
+ #
208
+ #TODO Works for two embedded levels. Dies with third and more levels.
398
209
  ########################################################################
399
210
  def duplicate_embedded(source) #:nodoc:
400
- # TODO Works for two embedded levels. Dies with third and more levels.
401
211
  dest = {}
402
212
  source.each do |attribute_name, value|
403
213
  next if attribute_name == '_id' # don't duplicate _id
214
+
404
215
  if value.class == Array
405
216
  dest[attribute_name] = []
406
217
  value.each do |ar|
407
218
  dest[attribute_name] << duplicate_embedded(ar)
408
219
  end
409
- else
410
- # if duplicate string must be added. Useful for unique attributes
220
+ else
221
+ # if duplicate, string dup is added. For unique fields
411
222
  add_duplicate = params['dup_fields'].to_s.match(attribute_name + ',')
412
223
  dest[attribute_name] = value
413
224
  dest[attribute_name] << ' dup' if add_duplicate
414
225
  end
415
226
  end
227
+ dest['created_at'] = Time.now if dest['created_at']
228
+ dest['updated_at'] = Time.now if dest['updated_at']
416
229
  dest
417
230
  end
418
231
 
419
232
  ########################################################################
420
233
  # Will create duplicate document of source document. This method is used for
421
- # duplicating document and is called from create action.
234
+ # duplicating document and is subroutine of create action.
422
235
  ########################################################################
423
236
  def duplicate_document(source)
424
237
  dest = {}
425
238
  source.attribute_names.each do |attribute_name|
426
239
  next if attribute_name == '_id' # don't duplicate _id
427
- # if duplicate, string must be added. Useful for unique attributes
240
+
241
+ # if duplicate, string dup is added. For unique fields
428
242
  add_duplicate = params['dup_fields'].to_s.match(attribute_name + ',')
429
243
  dest[attribute_name] = source[attribute_name]
430
244
  dest[attribute_name] << ' dup' if add_duplicate
431
245
  end
432
- # embedded documents
246
+ # embedded documents
433
247
  source.embedded_relations.keys.each do |embedded_name|
434
248
  next if source[embedded_name].nil? # it happens
249
+
435
250
  dest[embedded_name] = []
436
251
  source[embedded_name].each do |embedded|
437
252
  dest[embedded_name] << duplicate_embedded(embedded)
438
253
  end
439
254
  end
255
+ dest['created_at'] = Time.now if dest['created_at']
256
+ dest['updated_at'] = Time.now if dest['updated_at']
440
257
  dest
441
258
  end
442
259
 
@@ -444,33 +261,35 @@ end
444
261
  # Create (or duplicate) action. Action is also used for turning filter on.
445
262
  ########################################################################
446
263
  def create
447
- # abusing create for turning filter on
264
+ # abusing create for turning filter on
448
265
  return index if params[:filter].to_s == 'on'
449
- # not authorized
266
+
267
+ # not authorized
450
268
  unless dc_user_can(DcPermission::CAN_CREATE)
451
269
  flash[:error] = t('drgcms.not_authorized')
452
270
  return index
453
271
  end
454
- #
455
- if params['id'].nil? # create record
456
- # Prevent double form submit
272
+
273
+ # create document
274
+ if params['id'].nil?
275
+ # Prevent double form submit
457
276
  params[:form_time_stamp] = params[:form_time_stamp].to_i
458
277
  session[:form_time_stamp] ||= 0
459
278
  return index if params[:form_time_stamp] <= session[:form_time_stamp]
279
+
460
280
  session[:form_time_stamp] = params[:form_time_stamp]
461
- #
462
281
  create_new_empty_record
463
- params[:return_to] = 'index' if params[:commit] == t('drgcms.save&back') # save & back
464
282
  if save_data
465
- flash[:info] = t('drgcms.doc_saved')
283
+ flash[:info] = t('drgcms.doc_saved')
284
+ params[:return_to] = 'index' if params[:commit] == t('drgcms.save&back') # save & back
466
285
  return process_return_to(params[:return_to]) if params[:return_to]
467
286
 
468
- @parms['id'] = @record.id # must be set, for proper update link
469
- params[:id] = @record.id # must be set, for find_record
287
+ @parms['id'] = @record.id # must be set, for proper update link
288
+ params[:id] = @record.id # must be set, for find_record
470
289
  edit
471
- # render action: :edit
472
290
  else # error
473
291
  return process_return_to(params[:return_to]) if params[:return_to]
292
+
474
293
  render action: :new
475
294
  end
476
295
  else # duplicate record
@@ -492,9 +311,9 @@ def edit
492
311
  find_record
493
312
  if (m = callback_method('before_edit') )
494
313
  ret = call_callback_method(m)
495
- # Don't do anything if return is false
314
+ # don't do anything if return is false
496
315
  return index if ret.class == FalseClass
497
- end
316
+ end
498
317
  @parms['action'] = 'update'
499
318
  render action: :edit
500
319
  end
@@ -504,25 +323,27 @@ end
504
323
  ########################################################################
505
324
  def update
506
325
  find_record
507
- # check if record was not updated in mean time
326
+ # check if record was not updated in mean time
508
327
  if @record.respond_to?(:updated_at)
509
328
  if params[:last_updated_at].to_i != @record.updated_at.to_i
510
329
  flash[:error] = t('drgcms.updated_by_other')
511
330
  return render(action: :edit)
512
331
  end
513
332
  end
514
- #
333
+
515
334
  if dc_user_can(DcPermission::CAN_EDIT_ALL) or
516
335
  ( @record.respond_to?('created_by') and
517
336
  @record.created_by == session[:user_id] and
518
337
  dc_user_can(DcPermission::CAN_EDIT) )
519
- #
338
+
520
339
  if save_data
521
340
  params[:return_to] = 'index' if params[:commit] == t('drgcms.save&back') # save & back
522
341
  @parms['action'] = 'update'
523
- # Process return_to link
342
+ # Process return_to
524
343
  return process_return_to(params[:return_to]) if params[:return_to]
525
344
  else
345
+ # do not forget before_edit callback
346
+ if m = callback_method('before_edit') then call_callback_method(m) end
526
347
  return render action: :edit
527
348
  end
528
349
  else
@@ -536,7 +357,7 @@ end
536
357
  ########################################################################
537
358
  def destroy
538
359
  find_record
539
- # Which permission is required to delete
360
+ # check permission required to delete
540
361
  permission = if params['operation'].nil?
541
362
  if @record.respond_to?('created_by') # needs can_delete_all if created_by is present and not owner
542
363
  (@record.created_by == session[:user_id]) ? DcPermission::CAN_DELETE : DcPermission::CAN_DELETE_ALL
@@ -551,38 +372,39 @@ def destroy
551
372
  end
552
373
  end
553
374
  ok2delete = dc_user_can(permission)
554
- #
375
+
555
376
  case
556
- # not authorized
377
+ # not authorized
557
378
  when !ok2delete then
558
379
  flash[:error] = t('drgcms.not_authorized')
559
380
  return index
560
-
381
+
382
+ # delete document
561
383
  when params['operation'].nil? then
562
- # Process before delete callback
384
+ # before_delete callback
563
385
  if (m = callback_method('before_delete') )
564
386
  ret = call_callback_method(m)
565
- # Don't do anything if return is false
387
+ # don't do anything if return is false
566
388
  return index if ret.class == FalseClass
567
389
  end
568
- # document deleted
390
+
569
391
  if @record.destroy
570
392
  save_journal(:delete)
571
393
  flash[:info] = t('drgcms.record_deleted')
572
- # Process after delete callback
394
+ # after_delete callback
573
395
  if (m = callback_method('after_delete') )
574
396
  call_callback_method(m)
575
397
  elsif params['after-delete'].to_s.match('return_to')
576
398
  params[:return_to] = params['after-delete']
577
399
  end
578
- # Process return_to link
400
+ # Process return_to link
579
401
  return process_return_to(params[:return_to]) if params[:return_to]
580
402
  else
581
403
  flash[:error] = dc_error_messages_for(@record)
582
404
  end
583
405
  return index
584
406
 
585
- # deaktivate document
407
+ # deactivate document
586
408
  when params['operation'] == 'disable' then
587
409
  if @record.respond_to?('active')
588
410
  @record.active = false
@@ -592,7 +414,7 @@ def destroy
592
414
  flash[:info] = t('drgcms.doc_disabled')
593
415
  end
594
416
 
595
- # reaktivate document
417
+ # reactivate document
596
418
  when params['operation'] == 'enable' then
597
419
  if @record.respond_to?('active')
598
420
  @record.active = true
@@ -602,34 +424,90 @@ def destroy
602
424
  flash[:info] = t('drgcms.doc_enabled')
603
425
  end
604
426
 
605
- # reorder documents
427
+ #TODO reorder documents
606
428
  when params['operation'] == 'reorder' then
607
429
 
608
430
  end
609
- #
431
+
610
432
  @parms['action'] = 'update'
611
433
  render action: :edit
612
434
  end
613
435
 
436
+ ########################################################################
437
+ # Run action
438
+ ########################################################################
439
+ def run
440
+ # determine control file name and method
441
+ control_name, method_name = params[:control].split('.')
442
+ if method_name.nil?
443
+ method_name = control_name
444
+ control_name = params[:table]
445
+ end
446
+ # extend with control methods
447
+ extend_with_control_module(control_name)
448
+ if respond_to?(method_name)
449
+ # can it be called
450
+ return return_run_error t('drgcms.not_authorized') unless can_process_run
451
+ # call method
452
+ respond_to do |format|
453
+ format.json { send method_name }
454
+ format.html { send method_name }
455
+ end
456
+ else # Error message
457
+ return_run_error "Method #{method_name} not defined in #{control_name}_control"
458
+ end
459
+ end
460
+
614
461
  protected
615
462
 
616
- =begin
617
463
  ########################################################################
618
- # Processes on_save_ok form directive. Data is saved to session for
619
- # safety reasons.
464
+ # Respond with error on run action
465
+ ########################################################################
466
+ def return_run_error(text)
467
+ respond_to do |format|
468
+ format.json { render json: { msg_error: text } }
469
+ format.html { render plain: text }
470
+ end
471
+ end
472
+
473
+ ########################################################################
474
+ # Can run call be processed
475
+ ########################################################################
476
+ def can_process_run
477
+ if respond_to?(:dc_can_process)
478
+ response = send(:dc_can_process)
479
+ return response unless response.class == Array
480
+ else
481
+ response = [DcPermission::CAN_VIEW, params[:table] || 'dc_memory']
482
+ end
483
+ dc_user_can *response
484
+ end
485
+
486
+ ########################################################################
487
+ # Checks if user has permissions to perform operation on table and if not
488
+ # prepares response for not authorized message.
489
+ #
490
+ # @param [Integer] permission : Permission level defined in DcPermission constants eg. DcPermission::CAN_EDIT
491
+ # @param [String] collection_name : Table name on which user must have permission
492
+ #
493
+ # @return [Boolean] true when user has required permission otherwise false
620
494
  ########################################################################
621
- def process_on_save_ok
622
- session[:on_save_ok_id] = @record_id
623
- session[:on_save_ok_commit] = params[:commit]
624
- eval(params[:on_save_ok])
495
+ def user_has_permission?(permission, collection_name)
496
+ unless dc_user_can(permission, collection_name.to_s)
497
+ respond_to do |format|
498
+ format.json { render json: {msg_error: t('drgcms.not_authorized') } }
499
+ format.html { render plain: t('drgcms.not_authorized') }
500
+ end
501
+ return false
502
+ end
503
+ true
625
504
  end
626
- =end
627
505
 
628
506
  ########################################################################
629
- # Merges two forms when current form extends other form. Subroutine of read_drg_cms_form.
507
+ # Merges two forms when current form extends other form. Subroutine of read_drg_form.
630
508
  # With a little help of https://www.ruby-forum.com/topic/142809
631
509
  ########################################################################
632
- def forms_merge(hash1, hash2)
510
+ def forms_merge(hash1, hash2)
633
511
  target = hash1.dup
634
512
  hash2.keys.each do |key|
635
513
  if hash2[key].is_a? Hash and hash1[key].is_a? Hash
@@ -638,75 +516,152 @@ def forms_merge(hash1, hash2)
638
516
  end
639
517
  target[key] = hash2[key] == '/' ? nil : hash2[key]
640
518
  end
641
- # delete keys with nil value
642
- target.delete_if{ |k,v| v.nil? }
519
+ # delete keys with nil value
520
+ target.delete_if { |k, v| v.nil? }
521
+ end
522
+
523
+ ########################################################################
524
+ # Extends DRGCMS form file. Extended file is processed first and then merged
525
+ # with code in this form file. Form can extend only single form file.
526
+ #
527
+ # [Parameters:]
528
+ # [extend_option] : Value of @form['extend'] option
529
+ ########################################################################
530
+ def extend_drg_form(extend_option)
531
+ form_file_name = dc_find_form_file(extend_option)
532
+ @form_js << read_js_drg_form(form_file_name)
533
+ form = YAML.load_file( form_file_name )
534
+ @form = forms_merge(form, @form)
535
+ # If combined form contains tabs and fields options, merge fields into tabs
536
+ if @form['form']['tabs'] && @form['form']['fields']
537
+ @form['form']['tabs']['fields'] = @form['form']['fields']
538
+ @form['form']['fields'] = nil
539
+ end
643
540
  end
644
541
 
645
542
  ########################################################################
646
- # Read drgcms form into yaml object. Subroutine of check_authorization.
543
+ # Include code from another DRGCMS form file. Included code is merged
544
+ # with current form file code. Form can include more than one other DRGCMS forms.
545
+ #
546
+ # [Parameters:]
547
+ # [include_option] : Value of @form['include'] option
548
+ ########################################################################
549
+ def include_drg_form(include_option)
550
+ includes = include_option.class == Array ? include_option : include_option.split(/\,|\;/)
551
+ includes.each do |include_file|
552
+ form_file_name = dc_find_form_file(include_file)
553
+ @form_js << read_js_drg_form(form_file_name)
554
+ form = YAML.load_file(form_file_name)
555
+ @form = forms_merge(@form, form)
556
+ end
557
+ end
558
+
559
+ ########################################################################
560
+ # Will read data from form_file_name.js if exists.
561
+ #
562
+ # [Parameters:]
563
+ # [form_file_name] : Physical form filename
564
+ ########################################################################
565
+ def read_js_drg_form(form_file_name)
566
+ js_form_file_name = form_file_name.sub('.yml','.js')
567
+ File.read(js_form_file_name) rescue ''
568
+ end
569
+
647
570
  ########################################################################
648
- def read_drg_cms_form
571
+ # Read DRG form into @form object. Subroutine of check_authorization.
572
+ ########################################################################
573
+ def read_drg_form
649
574
  table_name = decamelize_type(params[:table].strip)
650
- @tables = table_name.split(';').inject([]) { |r,v| r << [v.classify.constantize, v] }
651
- # split ids passed when embedded document
575
+ @tables = table_name.split(';').inject([]) { |r,v| r << [(v.classify.constantize rescue nil), v] }
576
+
577
+ # split ids passed when embedded document
652
578
  ids = params[:ids].to_s.strip.downcase
653
579
  @ids = ids.split(';').inject([]) { |r,v| r << v }
654
- # form_name defaults to last table specified
580
+
581
+ # form_name defaults to last table specified
655
582
  form_name = params[:form_name] || @tables.last[1]
656
- @form = YAML.load_file( dc_find_form_file(form_name) ) rescue nil
657
- return unless @form
658
- # when form extends another form file.
659
- if @form['extend']
660
- form = YAML.load_file( dc_find_form_file(@form['extend']) )
661
- @form = forms_merge(form, @form)
662
- # If combined form contains tabs and fields options, merge fields into tabs
663
- if @form['form']['tabs'] and @form['form']['fields']
664
- @form['form']['tabs']['fields'] = @form['form']['fields']
665
- @form['form']['fields'] = nil
666
- end
667
- end
668
- # add readonly key to form if readonly parameter is passed in url
583
+ @form_js = ''
584
+
585
+ # dynamically generated form
586
+ @form = if params[:form_name] == 'method'
587
+ dc_eval_class_method(params[:form_method], params)
588
+ else
589
+ form_file_name = dc_find_form_file(form_name)
590
+ @form_js = read_js_drg_form(form_file_name)
591
+ YAML.load_file(form_file_name)
592
+ end
593
+
594
+ # form includes or extends another form file
595
+ include_drg_form(@form['include']) if @form['include']
596
+ extend_drg_form(@form['extend']) if @form['extend']
597
+ @form['script'] = (@form['script'].blank? ? @form_js : @form['script'] + @form_js)
598
+ # add readonly key to form if readonly parameter is passed in url
669
599
  @form['readonly'] = 1 if params['readonly'] #and %w(1 yes true).include?(params['readonly'].to_s.downcase.strip)
670
- # !!!!!! Always use strings for key names since @parms['table'] != @parms[:table]
600
+
601
+ # !!!!!! Always use strings for key names since @parms['table'] != @parms[:table]
671
602
  @parms = { 'table' => table_name, 'ids' => params[:ids], 'form_name' => form_name,
672
603
  'return_to' => params['return_to'], 'edit_only' => params['edit_only'],
673
604
  'readonly' => params['readonly']
674
605
  }
675
606
  end
676
607
 
608
+ ############################################################################
609
+ # Load module if available. Try not to mask errors in control module
610
+ ############################################################################
611
+ def load_controls_module(controls_string)
612
+ begin
613
+ controls_string.classify.constantize
614
+ rescue NameError => e
615
+ return nil if e.message.match('uninitialized constant') || e.message.match('wrong constant name')
616
+ # report errors when loading existing module
617
+ raise e
618
+ end
619
+ end
620
+
621
+ ############################################################################
622
+ # Dynamically extend cmsedit class with methods defined in controls module.
623
+ ############################################################################
624
+ def extend_with_control_module(control_name = @form['controls'] || @form['control'])
625
+ # May include embedded forms so ; => _
626
+ control_name ||= params[:table].gsub(';','_')
627
+ control_name += '_control' unless control_name.match(/control$|report$/i)
628
+ # p '************', control_name
629
+ controls = load_controls_module(control_name)
630
+ if controls
631
+ # extend first with dc_report when report
632
+ if control_name.match(/report$/i)
633
+ extend DcReport
634
+ init_report(control_name)
635
+ end
636
+ extend controls
637
+ # Form may be dynamically updated before processed
638
+ send(:dc_update_form) if respond_to?(:dc_update_form)
639
+ end
640
+ end
641
+
677
642
  ############################################################################
678
643
  # Check if user is authorized for the action. If authorization is in order it will also
679
644
  # load DRG form.
680
645
  ############################################################################
681
646
  def check_authorization
682
647
  params[:table] ||= params[:form_name]
683
- # Just show menu
684
- # return show if params[:action] == 'show'
648
+ # Only show menu
685
649
  return login if params[:id].in?(%w(login logout test))
686
650
  table = params[:table].to_s.strip.downcase
687
- # request shouldn't pass
651
+ set_default_guest_user_role if session[:user_roles].nil?
652
+ # request shouldn't pass
688
653
  if table != 'dc_memory' and
689
- (session[:user_roles].nil? or table.size < 3 or !dc_user_can(DcPermission::CAN_VIEW))
654
+ (table.size < 3 or !dc_user_can(DcPermission::CAN_VIEW))
690
655
  return render(action: 'error', locals: { error: t('drgcms.not_authorized')} )
691
656
  end
657
+ read_drg_form
658
+ return render( plain: t('drgcms.form_error') ) if @form.nil?
692
659
 
693
- read_drg_cms_form
694
-
695
- # Permissions can be also defined on form
696
- if @form.nil?
697
- render plain: t('drgcms.form_error')
698
- #TODO So far only can_view is used. Think about if using other permissions has sense
699
- elsif @form['permissions'].nil? or @form['permissions']['can_view'].nil? or
700
- dc_user_has_role(@form['permissions']['can_view'])
701
- # Extend class with methods defined in drgcms_controls module. May include embedded forms therefor ; => _
702
- controls_string = (@form['controls'] ? @form['controls'] : params[:table].gsub(';','_')) + '_control'
703
- controls = "DrgcmsControls::#{controls_string.classify}".constantize rescue nil
704
- # version next
705
- if controls.nil?
706
- controls_string = "#{@form['controls'] || params[:table].gsub(';','_')}_control"
707
- controls = "#{controls_string.classify}".constantize rescue nil
708
- end
709
- extend controls if controls
660
+ # Permissions can be also defined on form
661
+ #TODO So far only can_view is used. Think about if using other permissions has sense
662
+ can_view = @form.dig('permissions','can_view')
663
+ if can_view.nil? or dc_user_has_role(can_view)
664
+ extend_with_control_module
710
665
  else
711
666
  render(action: 'error', locals: { error: t('drgcms.not_authorized')} )
712
667
  end
@@ -728,7 +683,7 @@ end
728
683
  ########################################################################
729
684
  # Creates new empty record for new and create action.
730
685
  ########################################################################
731
- def create_new_empty_record(initial_data=nil) #:nodoc:
686
+ def create_new_empty_record(initial_data = nil) #:nodoc:
732
687
  if @tables.size == 1
733
688
  @record = @tables.first[0].new(initial_data)
734
689
  else
@@ -745,9 +700,9 @@ def update_standards(record = @record)
745
700
  record.updated_by = session[:user_id] if record.respond_to?('updated_by')
746
701
  if record.new_record?
747
702
  record.created_by = session[:user_id] if record.respond_to?('created_by')
748
- # set this only initialy. Allow to be set to nil on updates. This documents can then belong to all sites
749
- # and will be directly visible only to admins
750
- record.dc_site_id = dc_get_site._id if record.respond_to?('dc_site_id') and record.dc_site_id.nil?
703
+ # set this only initialy. Allow to be set to nil on updates. Document can then belong to all sites
704
+ # and will be directly visible only to admins
705
+ record.dc_site_id = dc_get_site.id if record.respond_to?('dc_site_id') && record.dc_site_id.nil?
751
706
  end
752
707
  end
753
708
 
@@ -759,17 +714,15 @@ end
759
714
  # [changes] Current document changed fields.
760
715
  ########################################################################
761
716
  def save_journal(operation, changes = {})
762
- # return unless session[:save_journal]
763
717
  if operation == :delete
764
718
  @record.attributes.each {|k,v| changes[k] = v}
765
- # elsif operation == :new
766
- # changes = {}
767
719
  end
768
- #
769
- if (operation != :update) or changes.size > 0
770
- # determine site_id
720
+
721
+ if (operation != :update) || changes.size > 0
722
+ # determine site_id
771
723
  site_id = @record.site_id if @record.respond_to?('site_id')
772
- site_id = dc_get_site._id if site_id.nil? and dc_get_site
724
+ site_id = dc_get_site._id if site_id.nil? && dc_get_site
725
+
773
726
  DcJournal.create(site_id: site_id,
774
727
  operation: operation,
775
728
  user_id: session[:user_id],
@@ -787,22 +740,23 @@ end
787
740
  # Returns callback method name or nil if not defined.
788
741
  ########################################################################
789
742
  def callback_method(key) #:nodoc:
790
- data_key = key.gsub('_','-') # data fields translate _ to -
791
- cb = case
743
+ data_key = key.gsub('_','-') # convert _ to -
744
+ callback = case
792
745
  when params['data'] && params['data'][data_key] then params['data'][data_key]
793
- # if dc_ + key method is present in model then it will be called automatically
746
+ # dc_ + key method is present then call it automatically
747
+ when @form['form'][key] then @form['form'][key]
794
748
  when respond_to?('dc_' + key) then 'dc_' + key
795
749
  when params[data_key] then params[data_key]
796
750
  else nil
797
751
  end
798
- #
752
+
799
753
  ret = case
800
- when cb.nil? then cb # otherwise there will be errors in next lines
801
- when cb.match('eval ') then cb.sub('eval ','')
802
- when cb.match('return_to ')
803
- params[:return_to] = cb.sub('return_to ','')
754
+ when callback.nil? then callback # otherwise there will be errors in next lines
755
+ when callback.match('eval ') then callback.sub('eval ','')
756
+ when callback.match('return_to ')
757
+ params[:return_to] = callback.sub('return_to ','')
804
758
  return nil
805
- else cb
759
+ else callback
806
760
  end
807
761
  ret
808
762
  end
@@ -841,16 +795,16 @@ end
841
795
 
842
796
  ########################################################################
843
797
  # Since tabs have been introduced on form it is a little more complicated
844
- # to get all edit fields on form. This method does it. Subroutine of save_data.
798
+ # to collect all edit fields on form. This method does it. Subroutine of save_data.
845
799
  ########################################################################
846
- def fields_on_form() #:nodoc:
800
+ def fields_on_form #:nodoc:
847
801
  form_fields = []
848
802
  if @form['form']['fields']
849
- # read only field elements (key is Integer)
850
- @form['form']['fields'].each {|key,options| form_fields << options if key.class == Integer }
803
+ # read only field elements (key is Integer)
804
+ @form['form']['fields'].each { |key, options| form_fields << options if key.class == Integer }
851
805
  else
852
806
  @form['form']['tabs'].keys.each do |tab|
853
- @form['form']['tabs'][tab].each {|key,options| form_fields << options if key.class == Integer }
807
+ @form['form']['tabs'][tab].each { |key, options| form_fields << options if key.class == Integer }
854
808
  end
855
809
  end
856
810
  form_fields
@@ -863,36 +817,262 @@ end
863
817
  def save_data
864
818
  form_fields = fields_on_form()
865
819
  return true if form_fields.size == 0
866
- #
820
+
867
821
  form_fields.each do |v|
868
822
  session[:form_processing] = v['name'] # for debuging
869
- next if v['type'].nil? or
823
+ next if v['type'].nil? or v['name'].nil? or
870
824
  v['type'].match('embedded') or # don't wipe embedded types
871
825
  (params[:edit_only] and params[:edit_only] != v['name']) or # otherwise other fields would be wiped
872
826
  v['readonly'] or # fields with readonly option don't return value and would be wiped
873
- !@record.respond_to?(v['name']) # there can be temporary fields on the form
827
+ !@record.respond_to?(v['name']) # there are temporary fields on the form
874
828
  # good to know! How to get type of field @record.fields[v['name']].type
875
829
  # return value from form field definition
876
830
  value = DrgcmsFormFields.const_get(v['type'].camelize).get_data(params, v['name'])
877
831
  @record.send("#{v['name']}=", value)
878
832
  end
879
- #
880
- operation = @record.new_record? ? :new : :update
881
- # controls callback method
833
+ # before_save callback
882
834
  if (m = callback_method('before_save') )
883
835
  ret = call_callback_method(m)
884
- # dont's save if callback method returns false
836
+ # don't save if callback returns false
885
837
  return false if ret.class == FalseClass
886
838
  end
887
- # save data
839
+
840
+ # save data
888
841
  changes = @record.changes
889
842
  update_standards() if changes.size > 0 # update only if there has been some changes
890
843
  if (saved = @record.save)
844
+ operation = @record.new_record? ? :new : :update
891
845
  save_journal(operation, changes)
892
- # callback methods
893
- if (m = callback_method('after_save') ) then call_callback_method(m) end
846
+ # after_save callback
847
+ if (m = callback_method('after_save') ) then call_callback_method(m) end
894
848
  end
895
849
  saved
896
850
  end
851
+
852
+ ########################################################################
853
+ # Will return comma separated data (field names) as array of symbols. For usage
854
+ # in select_fields and deny_fields
855
+ ########################################################################
856
+ def separated_to_symbols(data)
857
+ data.chomp.split(',').map { |e| e.strip.downcase.to_sym }
858
+ end
897
859
 
860
+ ########################################################################
861
+ # Will process only (select_fields) and without (deny_fields) option
862
+ ########################################################################
863
+ def process_select_and_deny_fields
864
+ only = @form['result_set']['select_fields'] || @form['result_set']['only']
865
+ @records = @records.only( separated_to_symbols(only) ) if only
866
+
867
+ without = @form['result_set']['deny_fields'] || @form['result_set']['without']
868
+ @records = @records.without( separated_to_symbols(without) ) if without
869
+ end
870
+
871
+ ########################################################################
872
+ # Will check and set sorting options for current result set. Subroutine of index method.
873
+ ########################################################################
874
+ def check_sort_options() #:nodoc:
875
+ table_name = @tables.first[1]
876
+ old_sort = session[table_name][:sort].to_s
877
+ sort, direction = old_sort.split(' ')
878
+
879
+ if params['sort']
880
+ # reverse sort if same selected
881
+ if params['sort'] == sort
882
+ direction = (direction == '1') ? '-1' : '1'
883
+ end
884
+ direction ||= '1'
885
+ sort = params[:sort]
886
+ session[table_name][:sort] = "#{params['sort']} #{direction}"
887
+ session[table_name][:page] = 1
888
+ end
889
+ @records.sort( sort => direction.to_i ) if session[table_name][:sort] && @records.class == Mongoid::Criteria
890
+ params['sort'] = nil # otherwise there is problem with other links
891
+ end
892
+
893
+ ########################################################################
894
+ # Set aditional filter options when filter is defined by filter method in control object.
895
+ ########################################################################
896
+ def user_filter_options(model) #:nodoc:
897
+ table_name = @tables.first[1]
898
+ if session[table_name]
899
+ DcFilter.get_filter(session[table_name][:filter]) || model
900
+ else
901
+ model
902
+ end
903
+ end
904
+
905
+ ########################################################################
906
+ # Return current sort options for model (table)
907
+ ########################################################################
908
+ def user_sort_options(model) #:nodoc:
909
+ table_name = (model.class == String ? model : model.to_s).underscore
910
+ return nil unless session[table_name][:sort]
911
+
912
+ field, direction = session[table_name][:sort].split(' ')
913
+ { field.to_sym => direction.to_i }
914
+ end
915
+
916
+ ########################################################################
917
+ # Will set session[table_name][:filter] and save last filter settings to session.
918
+ # subroutine of check_filter_options.
919
+ ########################################################################
920
+ def set_session_filter(table_name)
921
+ # models that can not be filtered (for now)
922
+ return if %w(dc_temp dc_memory).include?(params[:table])
923
+ # clear filter
924
+ if params[:filter] == 'off'
925
+ session[table_name][:filter] = nil
926
+ return
927
+ end
928
+ # field_name should exist on set filter condition
929
+ return if params[:filter_oper] && params[:filter_field].blank?
930
+
931
+ filter_value = if params[:filter_value].nil?
932
+ #NIL indicates that no filtering is needed
933
+ '#NIL'
934
+ else
935
+ if params[:filter_value].class == String and params[:filter_value][0] == '@'
936
+ # Internal value. Remove leading @ and evaluate expression
937
+ expression = DcInternals.get(params[:filter_value])
938
+ eval(expression) rescue nil
939
+ else
940
+ # No filter when empty
941
+ params[:filter_value] == '' ? '#NIL' : params[:filter_value]
942
+ end
943
+ end
944
+ # if filter field parameter is omitted then just set filter value
945
+ session[table_name][:filter] =
946
+ if params[:filter_field].nil?
947
+ saved = YAML.load(session[table_name][:filter])
948
+ saved['value'] = filter_value
949
+ saved.to_yaml
950
+ else
951
+ # as field defined. Split name and alternative input field
952
+ field = if params[:filter_field].match(' as ')
953
+ params[:filter_input] = params[:filter_field].split(' as ').last.strip
954
+ params[:filter_field].split(' as ').first.strip
955
+ else
956
+ params[:filter_field]
957
+ end
958
+
959
+ {'field' => field,
960
+ 'operation' => params[:filter_oper],
961
+ 'value' => filter_value,
962
+ 'input' => params[:filter_input],
963
+ 'table' => table_name }.to_yaml
964
+ end
965
+ # must be. Otherwise kaminari includes parames on paging links
966
+ params[:filter] = nil
967
+ params[:filter_id] = nil
968
+ params[:filter_oper] = nil
969
+ params[:filter_input] = nil
970
+ params[:filter_field] = nil
971
+ end
972
+
973
+ ########################################################################
974
+ # Will check and set current filter options for result set. Subroutine of index method.
975
+ ########################################################################
976
+ def check_filter_options() #:nodoc:
977
+ table_name = @tables.first[1]
978
+ model = @tables.first[0]
979
+ session[table_name] ||= {}
980
+ # page is set
981
+ session[table_name][:page] = params[:page] if params[:page]
982
+ # new filter is applied
983
+ if params[:filter]
984
+ set_session_filter(table_name)
985
+ session[table_name][:page] = 1
986
+ end
987
+ # if data model has field dc_site_id ensure that only documents which belong to the site are selected.
988
+ site_id = dc_get_site._id if dc_get_site
989
+
990
+ # don't filter site if no dc_site_id field or user is ADMIN
991
+ site_id = nil if !model.method_defined?('dc_site_id') or dc_user_can(DcPermission::CAN_ADMIN)
992
+ site_id = nil if session[table_name][:filter].to_s.match('dc_site_id')
993
+
994
+ if @records = DcFilter.get_filter(session[table_name][:filter])
995
+ @records = @records.and(dc_site_id: site_id) if site_id
996
+ else
997
+ @records = site_id ? model.where(dc_site_id: site_id) : model
998
+ end
999
+ process_select_and_deny_fields
1000
+ # pagination if required
1001
+ per_page = (@form['result_set']['per_page'] || 30).to_i
1002
+ @records = @records.page(session[table_name][:page]).per(per_page) if per_page > 0
1003
+ end
1004
+
1005
+ ########################################################################
1006
+ # Process index action for normal collections.
1007
+ ########################################################################
1008
+ def process_collections #:nodoc
1009
+ # If result_set is not defined on form, then it will fail. :return_to should know where to go
1010
+ if @form['result_set'].nil?
1011
+ process_return_to(params[:return_to] || 'reload')
1012
+ return true
1013
+ end
1014
+ # for now enable only filtering of top level documents
1015
+ if @tables.size == 1
1016
+ check_filter_options()
1017
+ check_sort_options()
1018
+ end
1019
+ # result set is defined by filter method in control object
1020
+ form_filter = @form['result_set']['filter']
1021
+ if form_filter
1022
+ if respond_to?(form_filter)
1023
+ @records = send(form_filter)
1024
+ # something went wrong. flash[] should have explanation.
1025
+ if @records.class == FalseClass
1026
+ @records = []
1027
+ render(action: :index)
1028
+ return true
1029
+ end
1030
+ process_select_and_deny_fields
1031
+ # pagination but only if not already set
1032
+ unless (@form['table'] == 'dc_memory' or @records.options[:limit])
1033
+ per_page = (@form['result_set']['per_page'] || 30).to_i
1034
+ @records = @records.page(params[:page]).per(per_page) if per_page > 0
1035
+ end
1036
+ elsif form_filter != 'dc_filter'
1037
+ Rails.logger.error "Error: result_set:filter: #{@form['result_set']['filter']} not found in controls!"
1038
+ end
1039
+ else
1040
+ if @tables.size > 1
1041
+ rec = @tables.first[0].find(@ids.first) # top most document.id
1042
+ 1.upto(@tables.size - 2) { |i| rec = rec.send(@tables[i][1].pluralize).find(@ids[i]) } # find embedded childrens by ids
1043
+ # TO DO. When field name is different then pluralized class name. Not working yet.
1044
+ embedded_field_name = @tables.last[0] ? @tables.last[1].pluralize : @tables.last[1]
1045
+ @records = rec.send(embedded_field_name) # current embedded set
1046
+ # sort by order if order field is present in model
1047
+ if @tables.last[1].classify.constantize.respond_to?(:order)
1048
+ @records = @records.order_by('order asc')
1049
+ end
1050
+ end
1051
+ end
1052
+ false
1053
+ end
1054
+
1055
+ ########################################################################
1056
+ # Process index action for in memory data.
1057
+ ########################################################################
1058
+ def process_in_memory #:nodoc
1059
+ @records = []
1060
+ # result set is defined by filter method in control object
1061
+ if (method = @form['result_set']['filter'])
1062
+ send(method) if respond_to?(method)
1063
+ end
1064
+ # result set is defined by class method
1065
+ if (klass_method = @form['result_set']['filter_method'])
1066
+ _klass, method = klass_method.split('.')
1067
+ klass = _klass.classify.constantize
1068
+ @records = klass.send(method) if klass.respond_to?(method)
1069
+ end
1070
+ # ensure that record has id field
1071
+ if @records.size > 0
1072
+ raise "Exception: id field must be set in dc_memory record!" unless @records.first.id
1073
+ end
1074
+ false
1075
+ end
1076
+
1077
+
898
1078
  end