drg_cms 0.4.39 → 0.4.53

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +49 -0
  3. data/app/assets/images/drg_cms/file_manager.png +0 -0
  4. data/app/assets/javascripts/drg_cms/drg_cms.js +8 -8
  5. data/app/assets/stylesheets/drg_cms/drg_cms.css +22 -20
  6. data/app/controllers/cmsedit_controller.rb +170 -114
  7. data/app/controllers/dc_application_controller.rb +142 -56
  8. data/app/controllers/dc_common_controller.rb +56 -34
  9. data/app/controllers/dc_main_controller.rb +1 -4
  10. data/app/controllers/drgcms_controls/dc_page_controls.rb +3 -0
  11. data/app/forms/all_options.yml +3 -0
  12. data/app/forms/cms_menu.yml +100 -117
  13. data/app/forms/dc_design.yml +1 -1
  14. data/app/forms/dc_ident.yml +37 -0
  15. data/app/forms/dc_menu_item.yml +1 -1
  16. data/app/forms/dc_permission.yml +1 -1
  17. data/app/forms/dc_site.yml +4 -0
  18. data/app/helpers/cmsedit_helper.rb +44 -80
  19. data/app/helpers/dc_ad_renderer.rb +27 -15
  20. data/app/helpers/dc_application_helper.rb +433 -196
  21. data/app/helpers/dc_big_menu_renderer.rb +40 -40
  22. data/app/helpers/dc_captcha_renderer.rb +38 -25
  23. data/app/helpers/dc_common_renderer.rb +15 -48
  24. data/app/helpers/dc_menu_renderer.rb +30 -20
  25. data/app/helpers/dc_page_renderer.rb +14 -18
  26. data/app/helpers/dc_part_renderer.rb +45 -16
  27. data/app/helpers/dc_piece_renderer.rb +23 -29
  28. data/app/helpers/dc_poll_renderer.rb +31 -20
  29. data/app/helpers/dc_renderer.rb +5 -4
  30. data/app/helpers/dc_simple_menu_renderer.rb +90 -68
  31. data/app/models/{__dc_global_data.rb → __dc_stat.rb} +20 -21
  32. data/app/models/dc_ad.rb +13 -1
  33. data/app/models/dc_ad_stat.rb +6 -0
  34. data/app/models/dc_big_menu.rb +15 -2
  35. data/app/models/dc_big_table.rb +27 -4
  36. data/app/models/dc_big_table_locale.rb +7 -0
  37. data/app/models/dc_big_table_value.rb +7 -0
  38. data/app/models/dc_category.rb +9 -3
  39. data/app/models/dc_design.rb +50 -0
  40. data/app/models/dc_dummy.rb +41 -1
  41. data/app/models/dc_folder_permission.rb +9 -2
  42. data/app/models/{dc_global_data.rb → dc_ident.rb} +20 -22
  43. data/app/models/dc_journal.rb +9 -1
  44. data/app/models/dc_key_value_store.rb +41 -4
  45. data/app/models/dc_link.rb +7 -0
  46. data/app/models/dc_menu.rb +20 -3
  47. data/app/models/dc_menu_item.rb +7 -0
  48. data/app/models/dc_page.rb +31 -12
  49. data/app/models/dc_part.rb +34 -4
  50. data/app/models/dc_permission.rb +32 -12
  51. data/app/models/dc_piece.rb +32 -4
  52. data/app/models/dc_policy.rb +17 -11
  53. data/app/models/dc_policy_role.rb +12 -7
  54. data/app/models/dc_policy_rule.rb +32 -4
  55. data/app/models/dc_poll.rb +8 -0
  56. data/app/models/dc_poll_item.rb +6 -0
  57. data/app/models/dc_simple_menu.rb +18 -3
  58. data/app/models/dc_simple_menu_item.rb +20 -2
  59. data/app/models/dc_site.rb +13 -3
  60. data/app/models/dc_stat.rb +8 -1
  61. data/app/models/dc_user.rb +18 -2
  62. data/app/models/dc_user_role.rb +7 -0
  63. data/app/models/dc_visit.rb +5 -0
  64. data/app/{helpers → models}/drgcms_form_field.rb +171 -73
  65. data/app/views/__dc_at_the_beginning/create.html.erb +9 -0
  66. data/app/views/__dc_at_the_beginning/index.html.erb +19 -0
  67. data/app/views/cmsedit/_edit_stuff.html.erb +2 -0
  68. data/app/views/cmsedit/_form.html.erb +0 -1
  69. data/app/views/dc_mail/subscribe.html.erb +0 -0
  70. data/config/initializers/kaminari_patch.rb +5 -4
  71. data/config/locales/drgcms_en.yml +4 -0
  72. data/config/locales/drgcms_sl.yml +1 -0
  73. data/config/locales/models_en.yml +14 -3
  74. data/config/locales/models_sl.yml +13 -4
  75. data/drg_cms.gemspec +4 -4
  76. data/lib/drg_cms.rb +37 -8
  77. data/lib/drg_cms/engine.rb +2 -2
  78. data/lib/drg_cms/version.rb +3 -2
  79. data/lib/tasks/at_the_beginning.yml +0 -0
  80. data/lib/tasks/dc_at_the_beginning.rake +118 -0
  81. data/lib/tasks/dc_cleanup.rake +19 -7
  82. data/lib/tasks/log_statistics.rb +66 -0
  83. data/lib/tasks/site_statistics.rake +29 -12
  84. data/test/dummy/app/controllers/application_controller.rb +1 -1
  85. data/test/dummy/app/helpers/application_helper.rb +1 -1
  86. metadata +15 -26
  87. data/README.rdoc +0 -3
  88. data/app/controllers/dc_at_the_beginning_controller.rb +0 -120
  89. data/app/controllers/dc_mail_controller.rb +0 -89
  90. data/app/forms/dc_forum_cat.yml +0 -54
  91. data/app/forms/dc_forum_forum.yml +0 -53
  92. data/app/forms/dc_forum_msg.yml +0 -124
  93. data/app/forms/dc_forum_privmsg.yml +0 -125
  94. data/app/forms/dc_forum_topic.yml +0 -131
  95. data/app/forms/dc_mail.yml +0 -88
  96. data/app/forms/dc_mail_address.yml +0 -56
  97. data/app/forms/dc_mail_list.yml +0 -44
  98. data/app/forms/dc_mail_list_member.yml +0 -42
  99. data/app/helpers/dc_mail_renderer.rb +0 -76
  100. data/app/models/dc_mail.rb +0 -64
  101. data/app/models/dc_mail_address.rb +0 -69
  102. data/app/models/dc_mail_list.rb +0 -48
  103. data/app/models/dc_mail_list_member.rb +0 -34
  104. data/app/models/dc_sendmail.rb +0 -48
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c72a699a0ff7d2c728862a4704654a2a23e826ba
4
- data.tar.gz: 162273135c2be3ca8e6ed94a6ee56e00eec2255a
3
+ metadata.gz: 2170ac5278d4127c49a981b33ffc4c7971ab2044
4
+ data.tar.gz: 0d227664c634c0169283c71a1cd3dde2b49a8015
5
5
  SHA512:
6
- metadata.gz: 22893cf485499702a541f39f41bb480cae7244a742f05c2ed5c9c29c37a62ccde3bdf622dd8af22f2bc8f3925bb9c2f8c3e073d68d025c7c7d11a4240f82ec64
7
- data.tar.gz: 9d9c0acaf0a7e8eaa27f945ad2e6fbe9e734cc23fc77282de50647bba0f80d98b416be80d993768f2149c3f7be198aefa0b7d07e34966f219afccacf9118d363
6
+ metadata.gz: dad0892b0d68cbaeed030987a03657e4b2fee598fb42f06bf961ed02a1e5b393201167c3fd391eed286270a22b791fc9a7e7aa3ec6a4ec9f1c8da958a573e990
7
+ data.tar.gz: c6a933b22b907d199464fe1099ec205a12800a2841c80d8c92a1f76cee167ad8f2a69db4f3382b8da843f0dd69319632799398e874038143dd8fd095cbc46495
@@ -0,0 +1,49 @@
1
+ # DrgCms
2
+
3
+ DRG CMS is cms build on strong foundations of Ruby on Rails and Mongo DB.
4
+
5
+ Project Tracking
6
+ ----------------
7
+
8
+ * [DrgCms Website and Documentation](http://www.drgcms.org)
9
+ * [DrgCms Testing website](http://test.drgcms.org)
10
+
11
+ Compatibility
12
+ -------------
13
+
14
+ DRG CMS is tested against MRI 1.9.3, 2.0.0, 2.1.0.
15
+
16
+ Documentation
17
+ -------------
18
+
19
+ Please see the DRG CMS website for up-to-date documentation:
20
+ [www.drgcms.org](http://www.drgcms.org)
21
+
22
+ License
23
+ -------
24
+
25
+ Copyright (c) 2012-2015 Damjan Rems
26
+
27
+ Permission is hereby granted, free of charge, to any person obtaining
28
+ a copy of this software and associated documentation files (the
29
+ "Software"), to deal in the Software without restriction, including
30
+ without limitation the rights to use, copy, modify, merge, publish,
31
+ distribute, sublicense, and/or sell copies of the Software, and to
32
+ permit persons to whom the Software is furnished to do so, subject to
33
+ the following conditions:
34
+
35
+ The above copyright notice and this permission notice shall be
36
+ included in all copies or substantial portions of the Software.
37
+
38
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
39
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
40
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
41
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
42
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
43
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
44
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
45
+
46
+ Credits
47
+ -------
48
+
49
+ Damjan Rems: damjan dot rems at gmail dot com
@@ -40,12 +40,12 @@ dumpAttributes = function(obj) {
40
40
  };
41
41
 
42
42
  /*******************************************************************
43
- * Used for removing background from iframe element.
43
+ * Used for removing background from iframe element. It is of course not working.
44
44
  *******************************************************************/
45
45
  remove_background_from_iframe = function(obj) {
46
46
  var head = obj.head;
47
47
  var css = '<style type="text/css">' +
48
- 'body{background: none;} ' +
48
+ 'body{background: none; background-picture:none; } ' +
49
49
  '</style>';
50
50
  $(head).append(css);
51
51
  };
@@ -226,10 +226,10 @@ $(document).ready( function() {
226
226
  // console.log(this.contentWindow.document.body.offsetHeight);
227
227
  if (this.contentWindow.document.body.offsetHeight > 10) {
228
228
  this.style.height = (this.contentWindow.document.body.offsetHeight + 30) + 'px';
229
- }
230
- remove_background_from_iframe(this.contentWindow.document);
231
229
  // scroll to it
232
- $('#iframe_edit').dc_scroll_view();
230
+ $('#iframe_edit').dc_scroll_view();
231
+ }
232
+ // remove_background_from_iframe(this.contentWindow.document);
233
233
  });
234
234
 
235
235
  /*******************************************************************
@@ -249,7 +249,7 @@ $(document).ready( function() {
249
249
  }
250
250
  else if (req == "post") {
251
251
  data = $('form').serialize();
252
- alert(data);
252
+ // alert(data);
253
253
  }
254
254
  else {
255
255
  data = {};
@@ -412,7 +412,7 @@ element = $(this).find(':first').attr('id');
412
412
  * Force reload of parent page if this div appears
413
413
  *******************************************************************/
414
414
  $('#div-reload-parent').load( function() {
415
- alert('div-reload-parent 1');
415
+ // alert('div-reload-parent 1');
416
416
  parent.location.href=parent.location.href
417
417
  });
418
418
 
@@ -420,7 +420,7 @@ element = $(this).find(':first').attr('id');
420
420
  * Force reload of parent page if this div appears
421
421
  *******************************************************************/
422
422
  $('#div-reload').load( function() {
423
- alert('div-reload 1');
423
+ // alert('div-reload 1');
424
424
  location.href=location.href
425
425
  });
426
426
 
@@ -24,27 +24,25 @@
24
24
  */
25
25
 
26
26
  body {
27
- font-family: helvetica;
28
- font-size: 13px;
29
- margin: 0px;
30
- vertical-align: middle;
31
- }
32
-
33
- .text-with-select {
34
- width: 24px;
27
+ font-family: helvetica;
28
+ font-size: 12px;
29
+ margin: 0px;
30
+ vertical-align: middle;
35
31
  }
36
32
 
37
33
  textarea, input, select {
38
- font-family: helvetica;
39
- font-size: 13px;
40
- padding: 4px;
41
- border: solid 1px #fff;
42
- box-shadow: rgba(0,0,0, 0.1) 0px 0px 4px;
43
- border-radius: 2px;
44
- background: linear-gradient(#ffe 2%, #fff 100%);
45
- color: #222;
34
+ /*font-family: helvetica;
35
+ font-size: 13px; */
36
+ padding: 4px;
37
+ border: solid 1px #888;
38
+ box-shadow: rgba(0,0,0, 0.1) 0px 0px 4px;
39
+ border-radius: 2px;
40
+ background: linear-gradient(#ffd 4%, #fff 100%);
41
+ color: #222;
46
42
  }
47
43
 
44
+ input { padding: 6px;}
45
+
48
46
  select#record_select { padding: 1px;}
49
47
 
50
48
  hr {
@@ -53,7 +51,6 @@ border: none;
53
51
  height: 2px;
54
52
  }
55
53
 
56
-
57
54
  .div {
58
55
  background-color: red;
59
56
  border: 0px;
@@ -78,6 +75,11 @@ a:link, a:active, a:visited { color: #c43; text-decoration: none; background: tr
78
75
  a:hover { text-decoration: none; color: #000; }
79
76
  a img { border: none; }
80
77
 
78
+
79
+ .text-with-select {
80
+ width: 24px;
81
+ }
82
+
81
83
  .no-borders {
82
84
  padding: 0px;
83
85
  border-spacing: 0px;
@@ -346,14 +348,14 @@ a img { border: none; }
346
348
  border-bottom: 1px solid #eee;
347
349
  }
348
350
  .dc-readonly {
349
- margin-left: 4px;
351
+ margin-left: 2px;
350
352
  margin-top: 2px;
351
353
  padding: 3px;
352
- border: solid 1px #ddd;
354
+ border: solid 1px #aaa;
353
355
  border-right: solid 1px #fff;
354
356
  border-bottom: 0px;
355
357
  border-radius: 2px;
356
- background: linear-gradient(#e8e8e8 2%, #fff 100%);
358
+ background: linear-gradient(#eee 1%, #fff 90%);
357
359
  }
358
360
 
359
361
  .dc-color-odd {
@@ -22,14 +22,66 @@
22
22
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  #++
24
24
 
25
+ ########################################################################
26
+ # This is main controller for processing actions by DRG forms. It provides
27
+ # CRUD actions for editing MongoDB documents. DRG CMS does not require controller
28
+ # to be made for every document model but centers all actions into single
29
+ # controller. Logic required to control data entry is provided within DRG
30
+ # forms which are loaded dynamically for every action.
31
+ #
32
+ # Most of data entry controls must therefore be done in document models definitions.
33
+ # And there are controls that cannot be done in document models. Like controls
34
+ # which include url parameters or accessing session variables. This is hard to be done
35
+ # in model therefore cmsedit_controls had to be invented. cmsedit_controls are
36
+ # modules with methods that are injected into cmsedit_controller and act in runtime like
37
+ # they are part of cmsedit_controller.
38
+ #
39
+ # Since Ruby and Rails provide some automagic loading of modules DRG CMS controls must be saved
40
+ # into app/controllers/drgcms_controls folder. Every model can have its own controls file.
41
+ # dc_page model's controls live in dc_page_controls.rb file. If model has embedded document
42
+ # its control's would be found in model_embedded_controls.rb. By convention module names
43
+ # are declared in camel case, so our dc_page_controls.rb declares DrgcmsControls::DcPageControls module.
44
+ #
45
+ # Controls (among other) may contain 6 fixed callback methods.
46
+ # These methods are:
47
+ # * dc_new_record
48
+ # * dc_before_edit
49
+ # * dc_before_save
50
+ # * dc_after_save
51
+ # * dc_before_delete
52
+ # * dc_after_delete
53
+ #
54
+ # Methods dc_before_edit, before_save or before_delete may also effect flow of the application. If
55
+ # method return false (not nil but FalseClass) normal flow of the program is interrupted and last operation
56
+ # is canceled.
57
+ #
58
+ # Second control methods that can be declared in DRG CMS controls are filters for
59
+ # viewing and sorting documents. It is often required that dynamic filters are
60
+ # applied to result_set documents.
61
+ #
62
+ # result_set:
63
+ # filter: current_users_documents
64
+ #
65
+ # Example implemented controls method:
66
+ #
67
+ # def current_users_documents
68
+ # if dc_user_can(DcPermission::CAN_READ)
69
+ # dc_page.where(created_by: session[:user_id])
70
+ # else
71
+ # flash[:error] = 'You can not perform this operation!'
72
+ # nil
73
+ # end
74
+ # end
75
+ #
76
+ # If filter method returns false user will be presented with flash error.
77
+ ########################################################################
25
78
  class CmseditController < DcApplicationController
26
- #before_filter :check_authorization, :except => [:login]
27
79
  before_action :check_authorization, :except => [:show, :login]
28
80
 
29
81
  ########################################################################
30
- # check_sort_options
82
+ # Will check and set sorting options for current result set. Subroutine of index method.
31
83
  ########################################################################
32
- def check_sort_options()
84
+ def check_sort_options() #:nodoc:
33
85
  table_name = @tables.first[1]
34
86
  old_sort = session[table_name][:sort].to_s
35
87
  sort, direction = old_sort.split(' ')
@@ -49,9 +101,9 @@ def check_sort_options()
49
101
  end
50
102
 
51
103
  ########################################################################
52
- # check_filter_options. As simple as possible
104
+ # Will check and set current filter options for result set. Subroutine of index method.
53
105
  ########################################################################
54
- def check_filter_options()
106
+ def check_filter_options() #:nodoc:
55
107
  table_name = @tables.first[1]
56
108
  session[table_name] ||= {}
57
109
  # process page
@@ -100,11 +152,18 @@ end
100
152
  ########################################################################
101
153
  def index
102
154
  # If result_set is not defined on form, then it will fail. :return_to should know where to go
103
- return process_return_to(params[:return_to]) if @form['result_set'].nil?
104
- #
155
+ if @form['result_set'].nil?
156
+ return process_return_to(params[:return_to] || 'reload')
157
+ end
158
+ # result set is defined by filter method in control object
105
159
  if @form['result_set']['filter']
106
160
  if respond_to?(@form['result_set']['filter'])
107
161
  @records = send @form['result_set']['filter']
162
+ # something iz wrong. flash[] should have explanation.
163
+ return render(action: :index) if @records.class == FalseClass
164
+ # pagination
165
+ per_page = (@form['result_set']['per_page'] || 30).to_i
166
+ @records = @records.page(params[:page]).per(per_page) if per_page > 0
108
167
  else
109
168
  p "Error: result_set:filter: #{@form['result_set']['filter']} not found in controls!"
110
169
  end
@@ -115,6 +174,7 @@ def index
115
174
  else
116
175
  rec = @tables.first[0].find(@ids.first) # top most document.id
117
176
  1.upto(@tables.size - 2) { |i| rec = rec.send(@tables[i][1].pluralize).find(@ids[i]) } # find embedded childrens by ids
177
+ # p rec,@tables, @tables.last[1].pluralize
118
178
  @records = rec.send(@tables.last[1].pluralize) # current embedded set
119
179
  # sort by order if order field is present in model
120
180
  if @tables.last[1].classify.constantize.respond_to?(:order)
@@ -130,39 +190,35 @@ def index
130
190
  end
131
191
 
132
192
  ########################################################################
133
- # Filter
193
+ # Filter action.
134
194
  ########################################################################
135
195
  def filter
136
196
  index
137
197
  end
138
198
 
139
199
  ########################################################################
140
- # Show is (ab)used to do some usefull things
200
+ # Show is (ab)used for direct login and logout into cmsedit controller. Login
201
+ # and logout actions can be directly performed by calling http://site.com/cmsedit/login
141
202
  ########################################################################
142
203
  def show
143
204
  case
144
205
  when params[:id].in?(%w(login logout)) then # show login menu
145
206
  session[:edit_mode] = 0
146
- # dc_collect_menu_forms
147
207
  render action: 'show', layout: 'cms'
148
- # when params[:id] == 'copy_clipboard'
149
- # return copy_clipboard
150
- # when params[:id] == 'paste_clipboard'
151
- # return paste_clipboard
152
208
  end
153
209
  end
154
210
 
155
211
  ########################################################################
156
212
  # Show is used to display menu
157
213
  ########################################################################
158
- def login
214
+ def login #:nodoc:
159
215
  # session[:edit_mode] = 0 if params[:id].in? %w(login logout) # show login menu
160
216
  # dc_collect_menu_forms
161
217
  render action: 'show', layout: 'cms'
162
218
  end
163
219
 
164
220
  ########################################################################
165
- # New action
221
+ # New action.
166
222
  ########################################################################
167
223
  def new
168
224
  if (m = callback_method('before_new') )
@@ -197,35 +253,55 @@ def new
197
253
  end
198
254
 
199
255
  ########################################################################
200
- # duplicate_record. For now not needed
256
+ # Duplicate embedded document. Since embedded documents are returned differently
257
+ # then top level document. Subroutine of duplicate_socument.
201
258
  ########################################################################
202
- =begin
203
- def duplicate_record(source, dest)
204
- # params['dup_fields'] += ',' if params['dup_fields'] # for easier field matching
205
- source.attribute_names.each do |attr_name|
206
- next if attr_name == '_id'
207
- p [attr_name, source[attr_name].class]
208
- if source[attr_name].class == Array
209
- # dest.save
210
- source[attr_name].each do |a|
211
- p a
212
- rec = dest.send(source[attr_name]).new
213
- duplicate_record(a, rec)
214
- rec.save!
215
- end
216
- else
217
- # if duplicate string must be added. Usefull for unique attributes
259
+ def duplicate_embedded(source) #:nodoc:
260
+ # TODO Works for two embedded levels. Dies with third and more levels.
261
+ dest = {}
262
+ source.each do |attr_name, value|
263
+ next if attr_name == '_id' # don't duplicate _id
264
+ if value.class == Array
265
+ dest[attr_name] = []
266
+ value.each do |ar|
267
+ dest[attr_name] << duplicate_embedded(ar)
268
+ end
269
+ else
270
+ # if duplicate string must be added. Useful for unique attributes
218
271
  add_duplicate = params['dup_fields'].to_s.match(attr_name + ',')
219
- p ["*",add_duplicate]
220
- dest.send("#{attr_name}=", source[attr_name])# + (add_duplicate ? ' duplicate' : '')) if source[attr_name] # can be nil
272
+ dest[attr_name] = value
273
+ dest[attr_name] << ' dup' if add_duplicate
221
274
  end
222
275
  end
223
- dest.save!
276
+ dest
224
277
  end
225
- =end
226
278
 
227
279
  ########################################################################
228
- # Create or duplicate action
280
+ # Will create duplicate document of source document. This method is used for
281
+ # duplicating document and is called from create action.
282
+ ########################################################################
283
+ def duplicate_document(source)
284
+ dest = {}
285
+ source.attribute_names.each do |attr_name|
286
+ next if attr_name == '_id' # don't duplicate _id
287
+ # if duplicate string must be added. Useful for unique attributes
288
+ add_duplicate = params['dup_fields'].to_s.match(attr_name + ',')
289
+ dest[attr_name] = source[attr_name]
290
+ dest[attr_name] << ' dup' if add_duplicate
291
+ end
292
+ #
293
+ source.embedded_relations.keys.each do |embedded_name|
294
+ next if source[embedded_name].nil? # it happens
295
+ dest[embedded_name] = []
296
+ source[embedded_name].each do |ar|
297
+ dest[embedded_name] << duplicate_embedded(ar)
298
+ end
299
+ end
300
+ dest
301
+ end
302
+
303
+ ########################################################################
304
+ # Create (or duplicate) action. Action is also used for turning filter on.
229
305
  ########################################################################
230
306
  def create
231
307
  # abusing create for turning filter on
@@ -250,16 +326,12 @@ def create
250
326
  end
251
327
  else # duplicate record
252
328
  find_record
253
- #create_new_empty_record
254
- #duplicate_record(@source, @record)
255
- dup = @record.dup
256
- dup.created_at = Time.now if dup.respond_to?('created_at') # yep it is also duplicated
329
+ params['dup_fields'] += ',' if params['dup_fields'] # for easier field matching
330
+ new_doc = duplicate_document(@record)
331
+ create_new_empty_record(new_doc)
332
+ update_standards()
333
+ @record.save!
257
334
 
258
- params['dup_fields'].to_s.split(',').each do |df|
259
- dup[df] = dup[df] + ' duplicate' if dup.respond_to?(df) # avoid errors
260
- end
261
- update_standards(dup)
262
- dup.save!
263
335
  index
264
336
  end
265
337
  end
@@ -277,22 +349,19 @@ def edit
277
349
  @parms['action'] = 'update'
278
350
  end
279
351
 
280
- =begin
281
- ########################################################################
282
- # TODO Think of better way for loginng and displaying menu
283
- # Show action.
284
- ########################################################################
285
- def show
286
- find_record
287
- # @parms['action'] = 'show'
288
- end
289
- =end
290
-
291
352
  ########################################################################
292
353
  # Update action.
293
354
  ########################################################################
294
355
  def update
295
356
  find_record
357
+ # check if record was not updated in mean time
358
+ if @record.respond_to?(:updated_at)
359
+ if params[:last_updated_at].to_i != @record.updated_at.to_i
360
+ flash[:error] = t('drgcms.updated_by_other')
361
+ return render(action: :edit)
362
+ end
363
+ end
364
+ #
296
365
  if dc_user_can(DcPermission::CAN_EDIT_ALL) or
297
366
  ( @record.respond_to?('created_by') and
298
367
  @record.created_by == session[:user_id] and
@@ -311,7 +380,7 @@ def update
311
380
  end
312
381
 
313
382
  ########################################################################
314
- # Destroy document
383
+ # Destroy action. Used also for enabling and disabling record.
315
384
  ########################################################################
316
385
  def destroy
317
386
  find_record
@@ -381,6 +450,7 @@ end
381
450
 
382
451
  protected
383
452
 
453
+ =begin
384
454
  ########################################################################
385
455
  # Processes on_save_ok form directive. Data is saved to session for
386
456
  # safety reasons.
@@ -390,11 +460,13 @@ def process_on_save_ok
390
460
  session[:on_save_ok_commit] = params[:commit]
391
461
  eval(params[:on_save_ok])
392
462
  end
463
+ =end
393
464
 
394
465
  ########################################################################
395
- # Merges two forms. With a little help of https://www.ruby-forum.com/topic/142809
466
+ # Merges two forms when current form extends other form. Subroutine of read_yaml.
467
+ # With a little help of https://www.ruby-forum.com/topic/142809
396
468
  ########################################################################
397
- def forms_merge(hash1, hash2)
469
+ def forms_merge(hash1, hash2)
398
470
  target = hash1.dup
399
471
  hash2.keys.each do |key|
400
472
  if hash2[key].is_a? Hash and hash1[key].is_a? Hash
@@ -408,7 +480,7 @@ def forms_merge(hash1, hash2)
408
480
  end
409
481
 
410
482
  ########################################################################
411
- # Read yaml form file
483
+ # Read drgcms form into yaml object. Subroutine of check_authorization.
412
484
  ########################################################################
413
485
  def read_yaml
414
486
  table_name = decamelize_type(params[:table].strip)
@@ -424,8 +496,8 @@ def read_yaml
424
496
  form = YAML.load_file( dc_find_form_file(@form['extend']) )
425
497
  @form = forms_merge(form, @form)
426
498
  end
427
- # add readonly key to form if readonly parameter is passed
428
- @form['readonly'] = 1 if @form['readonly'] and %w(1 yes true).include?(@form['readonly'].to_s.downcase.strip)
499
+ # add readonly key to form if readonly parameter is passed in url
500
+ @form['readonly'] = 1 if params['readonly'] and %w(1 yes true).include?(params['readonly'].to_s.downcase.strip)
429
501
  # p '2',@form
430
502
  # !!!!!! Always use strings for key names since @parms['table'] != @parms[:table]
431
503
  @parms = { 'table' => table_name, 'ids' => ids, 'formname' => formname,
@@ -433,10 +505,11 @@ def read_yaml
433
505
  end
434
506
 
435
507
  ############################################################################
436
- # Check if user is authorized for the action.
437
- # If everything is OK it also loads form definition.
508
+ # Check if user is authorized for the action. If authorization is in order it will also
509
+ # load DRG form.
438
510
  ############################################################################
439
511
  def check_authorization
512
+ params[:table] ||= params[:formname]
440
513
  # Extend class with methods defined in drgcms_controls module. May include embedded forms therefor ; => _
441
514
  controls_string = params[:table].gsub(';','_') + '_control'
442
515
  controls = ("DrgcmsControls::#{controls_string.classify}".constantize rescue nil)
@@ -459,9 +532,9 @@ def check_authorization
459
532
  end
460
533
 
461
534
  ########################################################################
462
- # Find record for edit, update or delete.
535
+ # Find current record (document) for edit, update or delete.
463
536
  ########################################################################
464
- def find_record
537
+ def find_record #:nodoc:
465
538
  if @tables.size == 1
466
539
  @record = @tables.first[0].find(params[:id])
467
540
  else
@@ -474,33 +547,18 @@ end
474
547
  ########################################################################
475
548
  # Creates new empty record for new and create action.
476
549
  ########################################################################
477
- def create_new_empty_record
550
+ def create_new_empty_record(initial_data=nil) #:nodoc:
478
551
  if @tables.size == 1
479
- @record = @tables.first[0].new
552
+ @record = @tables.first[0].new(initial_data)
480
553
  else
481
554
  rec = @tables.first[0].find(@ids.first) # top most record
482
555
  1.upto(@tables.size - 2) { |i| rec = rec.send(@tables[i][1].pluralize).find(@ids[i]) } # find embedded childrens by ids
483
- @record = rec.send(@tables.last[1].pluralize).new # new record
556
+ @record = rec.send(@tables.last[1].pluralize).new(initial_data) # new record
484
557
  end
485
558
  end
486
- =begin
487
- ########################################################################
488
- # Get data for multitext_autocomplete field. That is field which is saved as record[kats_****]
489
- #
490
- # @param [ name ] Name of field
491
- ########################################################################
492
- def get_data_multitext_autocomplete(name)
493
- r = []
494
- params['record'].each do |k,v|
495
- # if it starts with - then it was removed
496
- r << BSON::ObjectId(v) if k.match("#{name}_") and v[0,1] != '-'
497
- end
498
- r.uniq!
499
- r
500
- end
501
- =end
559
+
502
560
  ########################################################################
503
- # update_standard fields like updated_by, created_by
561
+ # Update standard fields like updated_by, created_by, site_id
504
562
  ########################################################################
505
563
  def update_standards(record = @record)
506
564
  record.updated_by = session[:user_id] if record.respond_to?('updated_by')
@@ -514,9 +572,9 @@ end
514
572
 
515
573
  ########################################################################
516
574
  # Since tabs have been introduced on form it is a little more complicated
517
- # to get all active field names on form. This method does it.
575
+ # to get all edit fields on form. This method does it. Subroutine of save_data.
518
576
  ########################################################################
519
- def fields_on_form()
577
+ def fields_on_form() #:nodoc:
520
578
  fields = []
521
579
  if @form['form']['fields']
522
580
  # second element of array is hash. Get only hash element
@@ -530,14 +588,11 @@ def fields_on_form()
530
588
  end
531
589
 
532
590
  ########################################################################
533
- # Save changes to journal table. Saves all parameters to retrive record if needed.
534
- #
535
- # @example usage before save
536
- # save_journal(@record.changes)
537
- # @example usage on delete
538
- # save_journal(true)
539
- #
540
- # @param [ changes ] Changes for the record
591
+ # Save document changes to journal table. Saves all parameters to retrieve record if needed.
592
+ #
593
+ # [Parameters:]
594
+ # [operation] 'delete' or 'update'.
595
+ # [changes] Current document changed fields.
541
596
  ########################################################################
542
597
  def save_journal(operation, changes = {})
543
598
  # return unless session[:save_journal]
@@ -564,10 +619,10 @@ def save_journal(operation, changes = {})
564
619
  end
565
620
 
566
621
  ########################################################################
567
- # Determines if callback method is defined in parameters or in model.
622
+ # Determines if callback method is defined in parameters or in control module.
568
623
  # Returns callback method name or nil if not defined.
569
624
  ########################################################################
570
- def callback_method(key)
625
+ def callback_method(key) #:nodoc:
571
626
  data_key = key.gsub('_','-') # data fields translate _ to -
572
627
  cb = case
573
628
  when params['data'] && params['data'][data_key] then params['data'][data_key]
@@ -576,7 +631,6 @@ def callback_method(key)
576
631
  when params[key] then params[key]
577
632
  else nil
578
633
  end
579
- # p [ '***********************',key, cb, params['data'],params['key']]
580
634
  #
581
635
  ret = case
582
636
  when cb.nil? then cb # otherwise there will be errors in next lines
@@ -592,19 +646,22 @@ end
592
646
  ########################################################################
593
647
  # Calls callback method.
594
648
  ########################################################################
595
- def call_callback_method(m)
649
+ def call_callback_method(m) #:nodoc:
596
650
  send(m) if respond_to?(m)
597
651
  end
598
652
 
599
653
  ########################################################################
600
- # Same as javascript_tag helper
654
+ # Same as javascript_tag helper. Ajax form actions may results in javascript code to be returned.
655
+ # This will add javascript tag to code.
601
656
  ########################################################################
602
- def js_tag(script)
657
+ def js_tag(script) #:nodoc:
603
658
  "<script type=\"text/javascript\">#{script}</script>"
604
659
  end
605
660
 
606
661
  ########################################################################
607
- # Process return_to parameter when set on a form or set by callbacks.
662
+ # Process return_to parameter when defined on form or set by controls methods.
663
+ # params['return_to'] may contain 'index', 'reload' or 'parent.reload' or any valid url to
664
+ # return to, after successful controls method call.
608
665
  ########################################################################
609
666
  def process_return_to(return_to)
610
667
  script = case
@@ -617,37 +674,34 @@ def process_return_to(return_to)
617
674
  end
618
675
 
619
676
  ########################################################################
620
- # Save_data. Save only fields on form.
677
+ # Save edited data. Take care that only fields defined on form are affected.
678
+ # It also saves journal data and calls before_save and after_save callbacks.
621
679
  ########################################################################
622
680
  def save_data
623
681
  fields = fields_on_form()
624
- p fields
625
682
  return true unless fields.size > 0
626
683
  #
627
684
  fields.each do |v|
628
685
  next if v['type'].match('embedded') # don't wipe embedded fields
629
686
  next if params[:edit_only] and params[:edit_only] != v['name'] # otherwise other fields would be wiped
630
687
  next unless @record.respond_to?(v['name']) # there can be temporary fields on the form
631
- #
632
- # TODO I used to ignore readonly fields. check if this is OK
633
- # next if v['type'] == 'readonly' or v['readonly'] # ignore readonly fields
634
688
  # return value from form field definition
635
689
  value = DrgcmsFormField.const_get(v['type'].camelize).get_data(params, v['name'])
636
690
  @record.send("#{v['name']}=", value)
637
691
  end
638
- #
639
- update_standards()
692
+ #
640
693
  operation = @record.new_record? ? :new : :update
641
- # callback methods
694
+ # controls callback method
642
695
  if (m = callback_method('before_save') )
643
696
  ret = call_callback_method(m)
644
697
  # dont's save if callback method returns false
645
698
  return false if ret.class == FalseClass
646
699
  end
647
- # check if model has dc_before_save method
700
+ # maybe model has dc_before_save method defined. Call it.
648
701
  @record.dc_before_save(self) if @record.respond_to?('dc_before_save')
649
702
  #
650
703
  changes = @record.changes
704
+ update_standards() if changes.size > 0 # update only if there has been some changes
651
705
  if (saved = @record.save)
652
706
  save_journal(operation, changes)
653
707
  # callback methods
@@ -658,6 +712,7 @@ def save_data
658
712
  saved
659
713
  end
660
714
 
715
+ =begin
661
716
  ########################################################################
662
717
  # Returns true if model has field defined. This might be defined by mongoid,
663
718
  # but I didn't found method.
@@ -669,5 +724,6 @@ def model_has_field?(model, field_name)
669
724
  model.fields.each {|f| return true if f.first == field_name.to_s}
670
725
  false
671
726
  end
727
+ =end
672
728
 
673
729
  end