drg_cms 0.7.0.2 → 0.7.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/drg_cms/drg_cms.js +110 -35
  3. data/app/assets/javascripts/drg_cms/jquery.bpopup.js +372 -0
  4. data/app/assets/javascripts/drg_cms_application.js +1 -1
  5. data/app/assets/javascripts/drg_cms_cms.js +1 -1
  6. data/app/assets/stylesheets/drg_cms/drg_cms.css +126 -36
  7. data/app/assets/stylesheets/drg_cms/select-multiple.css +6 -7
  8. data/app/controllers/cmsedit_controller.rb +78 -47
  9. data/app/controllers/dc_application_controller.rb +22 -25
  10. data/app/controllers/dc_common_controller.rb +9 -6
  11. data/app/controllers/dc_main_controller.rb +0 -1
  12. data/app/controls/{dc_category_control.rb → dc_gallery_control.rb} +15 -30
  13. data/app/controls/dc_image_control.rb +180 -0
  14. data/app/controls/dc_page_control.rb +3 -3
  15. data/app/controls/dc_poll_result_control.rb +38 -39
  16. data/app/controls/dc_report.rb +9 -4
  17. data/app/controls/dc_setup_control.rb +53 -0
  18. data/app/controls/design_element_settings_control.rb +88 -37
  19. data/app/forms/all_options.yml +20 -9
  20. data/app/forms/cms_menu.yml +14 -2
  21. data/app/forms/dc_gallery.yml +1 -1
  22. data/app/forms/dc_image.yml +122 -0
  23. data/app/forms/dc_image_search.yml +72 -0
  24. data/app/forms/dc_page.yml +11 -8
  25. data/app/forms/dc_poll.yml +2 -1
  26. data/app/forms/dc_poll_result.yml +10 -7
  27. data/app/forms/dc_setup.yml +45 -0
  28. data/app/forms/dc_steps_template.yml +6 -2
  29. data/app/helpers/cms_common_helper.rb +36 -24
  30. data/app/helpers/cms_edit_helper.rb +26 -33
  31. data/app/helpers/cms_helper.rb +29 -12
  32. data/app/helpers/cms_index_helper.rb +109 -80
  33. data/app/helpers/dc_application_helper.rb +108 -86
  34. data/app/helpers/dc_image_helper.rb +127 -0
  35. data/app/models/concerns/dc_policy_rule_concern.rb +1 -1
  36. data/app/models/concerns/dc_user_concern.rb +13 -5
  37. data/app/models/dc_big_table.rb +1 -1
  38. data/app/models/dc_category.rb +12 -0
  39. data/app/models/dc_design.rb +5 -4
  40. data/app/models/dc_filter.rb +24 -27
  41. data/app/models/dc_image.rb +237 -0
  42. data/app/models/dc_internals.rb +5 -9
  43. data/app/models/dc_memory.rb +2 -2
  44. data/app/models/dc_policy_role.rb +8 -8
  45. data/app/models/dc_setup.rb +111 -0
  46. data/app/models/drgcms_form_fields/datetime_picker.rb +1 -1
  47. data/app/models/drgcms_form_fields/drgcms_field.rb +9 -26
  48. data/app/models/drgcms_form_fields/embedded.rb +28 -17
  49. data/app/models/drgcms_form_fields/journal_diff.rb +2 -2
  50. data/app/models/drgcms_form_fields/multitext_autocomplete.rb +88 -76
  51. data/app/models/drgcms_form_fields/select.rb +41 -19
  52. data/app/models/drgcms_form_fields/text_with_select.rb +5 -9
  53. data/app/renderers/dc_big_menu_renderer.rb +18 -20
  54. data/app/renderers/dc_gallery_renderer.rb +10 -4
  55. data/app/renderers/dc_menu_renderer.rb +21 -58
  56. data/app/renderers/dc_page_renderer.rb +7 -7
  57. data/app/renderers/dc_poll_renderer.rb +13 -12
  58. data/app/renderers/dc_simple_menu_renderer.rb +1 -1
  59. data/app/views/cmsedit/_edit_stuff.html.erb +4 -1
  60. data/app/views/cmsedit/edit.html.erb +1 -1
  61. data/app/views/cmsedit/index.html.erb +1 -1
  62. data/app/views/cmsedit/new.html.erb +1 -0
  63. data/config/locales/drgcms_en.yml +22 -2
  64. data/config/locales/drgcms_sl.yml +25 -6
  65. data/config/locales/models_en.yml +50 -1
  66. data/config/locales/models_sl.yml +60 -1
  67. data/drg_cms.gemspec +1 -1
  68. data/lib/drg_cms/version.rb +1 -1
  69. data/lib/drg_cms.rb +40 -27
  70. data/lib/generators/convert_to_ar/USAGE +8 -0
  71. data/lib/generators/convert_to_ar/convert_to_ar_generator.rb +158 -0
  72. data/lib/generators/new_drg_form/new_drg_form_generator.rb +32 -14
  73. metadata +19 -10
  74. data/app/assets/javascripts/drg_cms/jquery.bpopup.min.js +0 -7
  75. data/app/views/layouts/__cmsedit.html.erb +0 -16
@@ -260,7 +260,7 @@ def dc_table_title(text, result_set = nil)
260
260
  c = %(<div class="dc-title">#{text})
261
261
  c << dc_help_button(result_set)
262
262
 
263
- if result_set && result_set.respond_to?(:current_page)
263
+ if result_set&.respond_to?(:current_page)
264
264
  c << %(<div class="dc-paginate">#{paginate(result_set, :params => {action: 'index', clear: 'no', filter: nil})}</div>)
265
265
  end
266
266
  c << '<div style="clear: both;"></div></div>'
@@ -268,26 +268,27 @@ def dc_table_title(text, result_set = nil)
268
268
  end
269
269
 
270
270
  ############################################################################
271
- # Creates title for cmsedit edit action dialog.
272
- #
271
+ # Creates title for cmsedit edit action dialog.
272
+ #
273
273
  # Returns:
274
274
  # String. HTML code for title.
275
275
  ############################################################################
276
276
  def dc_edit_title
277
277
  session[:form_processing] = "form:title:"
278
- title = @form['form']['title']
278
+ title_data = @form['form']['title']
279
+ if title_data.class == String
280
+ t(title_data, title_data)
279
281
  # defined as form:title:edit
280
- if title && title['edit'] && !@form['readonly']
281
- t( title['edit'], title['edit'] )
282
- elsif title && title['show'] && @form['readonly']
283
- t( title['show'], title['show'] )
282
+ elsif title_data&.dig('edit') && !@form['readonly']
283
+ t( title_data['edit'], title_data['edit'] )
284
+ elsif title_data&.dig('show') && @form['readonly']
285
+ t( title_data['show'], title_data['show'] )
284
286
  else
285
- # concatenate title
286
287
  c = (@form['readonly'] ? t('drgcms.show') : t('drgcms.edit')) + " : "
287
288
  c << (@form['title'].class == String ? t( @form['title'], @form['title'] ) : t_tablename(@form['table']))
288
- title = title.try('field')
289
-
290
- c << "#{@record[ title ]}" if title && @record.respond_to?(title)
289
+ # add description field value to title
290
+ field_name = title_data['field'] if title_data
291
+ c << " : #{@record[ field_name ]}" if field_name && @record.respond_to?(field_name)
291
292
  c
292
293
  end
293
294
  end
@@ -300,14 +301,18 @@ end
300
301
  ############################################################################
301
302
  def dc_new_title
302
303
  session[:form_processing] = "form:title:"
303
- title = @form['form']['title']
304
+ title_data = @form['form']['title']
305
+ if title_data.class == String
306
+ t(title_data, title_data)
304
307
  # defined as form:title:new
305
- if title && title['new']
306
- t( title['new'], title['new'] )
308
+ elsif title_data&.dig('new')
309
+ t( title_data['new'], title_data['new'] )
307
310
  else
308
311
  # in memory structures
309
312
  if @form['table'] == 'dc_memory'
310
- t( @form['title'], @form['title'] )
313
+ return t( @form['title'], @form['title'] ) if @form['title']
314
+
315
+ t("#{@form['i18n_prefix']}.tabletitle", '')
311
316
  else
312
317
  "#{t('drgcms.new')} : #{t_tablename(@form['table'])}"
313
318
  end
@@ -684,51 +689,40 @@ end
684
689
  ############################################################################
685
690
  # Returns list of all collections (tables) as array of choices for usage in select fields.
686
691
  # List is collected from cms_menu.yml files and may not include all collections used in application.
687
- # Currently list is only used for helping defining collection names on dc_permission form.
688
- #
692
+ # Currently list is only used for helping defining collection names on dc_permission form.
693
+ #
689
694
  # Example (as used in forms):
690
695
  # form:
691
696
  # fields:
692
697
  # 10:
693
698
  # name: table_name
694
699
  # type: text_with_select
695
- # eval: dc_choices4_all_collections
700
+ # eval: dc_choices4_all_collections
696
701
  ############################################################################
697
702
  def dc_choices4_all_collections
698
- choices = {}
699
- DrgCms.paths(:forms).reverse.each do |path|
700
- filename = "#{path}/cms_menu.yml"
701
- next unless File.exist?(filename)
702
-
703
- menu = YAML.load_file(filename) rescue nil # load menu
704
- next if menu.nil? or !menu['menu'] # not menu or error
705
- menu['menu'].each do |section|
706
- next unless section.last['items'] # next if no items
707
- section.last['items'].each do |k, v| # look for caption and
708
- key = v['table']
709
- choices[key] ||= "#{key} - #{t(v['caption'], v['caption'])}"
710
- end
711
- end
712
- end
713
- choices.invert.to_a.sort # hash has to be inverted for values to be returned right
703
+ models = Mongoid.models.map(&:to_s).uniq.map(&:underscore).delete_if { |e| e.match('/') }
704
+ models.sort.inject([]) do |r, model_name|
705
+ r << ["#{model_name} - #{t("helpers.label.#{model_name}.tabletitle", '')}", model_name]
706
+ end
714
707
  end
715
708
 
716
709
  ##########################################################################
717
- # Returns choices for creating collection edit select field on CMS top menu.
710
+ # Code for top CMS menu.
718
711
  ##########################################################################
719
- def dc_choices4_cmsmenu
712
+ def dc_cms_menu
720
713
  menus = {}
721
714
  DrgCms.paths(:forms).reverse.each do |path|
722
715
  filename = "#{path}/cms_menu.yml"
723
- next unless File.exist?(filename)
724
- menu = YAML.load_file(filename) rescue nil # load menu
725
- next if menu.nil? or !menu['menu'] # not menu or error
726
- menus = CmsHelper.forms_merge(menu['menu'], menus) # ignore top level part
727
- end
716
+ next if !File.exist?(filename)
717
+
718
+ menu = YAML.load_file(filename) rescue nil # load menu
719
+ menus = CmsHelper.forms_merge(menu['menu'], menus) if menu.dig('menu') # merge menus
720
+ end
728
721
 
729
722
  html = '<ul>'
730
723
  menus.to_a.sort.each do |index, menu| # sort menus, result is array of sorted hashes
731
724
  next unless menu['caption']
725
+
732
726
  icon = menu['icon'].match('/') ? image_tag(menu['icon']) : fa_icon(menu['icon']) #external or fa- image
733
727
  html << %(<li class="cmsedit-top-level-menu"><div>#{icon}#{t(menu['caption'])}</div><ul>)
734
728
  menu['items'].to_a.sort.each do |index1, value| # again, sort menu items first
@@ -736,19 +730,18 @@ def dc_choices4_cmsmenu
736
730
  opts = { target: value['target'] || 'iframe_cms' }
737
731
  "<li>#{dc_link_to(t(value['caption']), value['icon'] || '', value['link'], opts)}</li>"
738
732
  else
739
- opts =
740
- { controller: value['controller'],
741
- action: value['action'],
742
- table: value['table'],
743
- form_name: value['form_name'] || value['table'],
744
- target: value['target'] || 'iframe_cms',
745
- }
733
+ opts = { controller: value['controller'], action: value['action'],
734
+ table: value['table'], form_name: value['form_name'] || value['table'],
735
+ target: value['target'] || 'iframe_cms',
736
+ }
737
+ # additional parameters
738
+ value['params'].each { |k, v| opts[k] = dc_value_for_parameter(v) } if value['params']
746
739
  "<li>#{dc_link_to(t(value['caption']), value['icon'] || '', opts)}</li>"
747
740
  end
748
741
  end
749
742
  html << '</ul></li>'
750
743
  end
751
- html
744
+ html.html_safe
752
745
  end
753
746
 
754
747
  ############################################################################
@@ -760,7 +753,7 @@ def dc_choices4_folders_list
760
753
  home = File.join(public,dc_get_site.files_directory)
761
754
  choices = Dir.glob(home + '/**/*/').select { |fn| File.directory?(fn) }
762
755
  choices << home # add home
763
- choices.collect! {|e| e.gsub(public,'')} # remove public part
756
+ choices.collect! { |e| e.gsub(public,'') } # remove public part
764
757
  choices.sort
765
758
  end
766
759
 
@@ -782,7 +775,7 @@ end
782
775
  # type: select
783
776
  # eval: dc_choices4('dc_poll','name','_id')
784
777
  ############################################################################
785
- def dc_choices4(model, name, id='_id', options = {})
778
+ def dc_choices4(model, name, id = '_id', options = {})
786
779
  model = model.classify.constantize
787
780
  qry = model.only(id, name)
788
781
  if (param = options[:site])
@@ -792,8 +785,6 @@ def dc_choices4(model, name, id='_id', options = {})
792
785
  end
793
786
  qry = qry.and(active: true) if model.method_defined?(:active)
794
787
  qry = qry.order_by(name => 1).collation(locale: I18n.locale.to_s)
795
- #choices = qry.inject([]) {|result,e| result << [ e[name], e[id] ]}
796
- #choices.sort_alphabetical_by(&:first) # use UTF-8 sort
797
788
  qry.map { |e| [e[name], e[id]] }
798
789
  end
799
790
 
@@ -864,10 +855,10 @@ def dc_user_can_view(ctrl, policy_id)
864
855
  policies = if site.inherit_policy.blank?
865
856
  site.dc_policies
866
857
  else
867
- Mongoid::QueryCache.cache { DcSite.find(site.inherit_policy) }.dc_policies
858
+ Mongo::QueryCache.cache { DcSite.find(site.inherit_policy) }.dc_policies
868
859
  end
869
860
  # permission defined by default policy
870
- default_policy = Mongoid::QueryCache.cache { policies.find_by(is_default: true) }
861
+ default_policy = Mongo::QueryCache.cache { policies.find_by(is_default: true) }
871
862
  return cache_add(policy_id, false, 'Default access policy not found for the site!') unless default_policy
872
863
 
873
864
  permissions = {}
@@ -875,14 +866,14 @@ def dc_user_can_view(ctrl, policy_id)
875
866
  # update permissions with defined policy
876
867
  part_policy = nil
877
868
  if policy_id
878
- part_policy = Mongoid::QueryCache.cache { policies.find(policy_id) }
869
+ part_policy = Mongo::QueryCache.cache { policies.find(policy_id) }
879
870
  return cache_add(policy_id, false, 'Access policy not found for part!') unless part_policy
880
871
 
881
872
  part_policy.dc_policy_rules.to_a.each { |v| permissions[v.dc_policy_role_id] = v.permission }
882
873
  end
883
874
  # apply guest role if no roles defined
884
875
  if ctrl.session[:user_roles].nil?
885
- role = Mongoid::QueryCache.cache { DcPolicyRole.find_by(system_name: 'guest', active: true) }
876
+ role = Mongo::QueryCache.cache { DcPolicyRole.find_by(system_name: 'guest', active: true) }
886
877
  return cache_add(policy_id, false, 'System guest role not defined!') unless role
887
878
 
888
879
  ctrl.session[:user_roles] = [role.id]
@@ -1008,7 +999,15 @@ def dc_big_table(key)
1008
999
  desc = v.value if desc.blank? # still blank. Use value as description
1009
1000
  ret << [desc, v.value]
1010
1001
  end
1011
- ret
1002
+ ret.sort_alphabetical_by(&:first)
1003
+ end
1004
+
1005
+ ########################################################################
1006
+ # Will return name for value defined in dc_big_table
1007
+ ########################################################################
1008
+ def dc_big_table_name_for_value(key, value)
1009
+ dc_big_table(key).each { |k, val| return k if val.to_s == value.to_s}
1010
+ '???'
1012
1011
  end
1013
1012
 
1014
1013
  ########################################################################
@@ -1073,25 +1072,25 @@ end
1073
1072
  ########################################################################
1074
1073
  def dc_internal_var(object, var_name, current_document = nil)
1075
1074
  begin
1076
- case
1077
- when object == 'session' then _origin.session[var_name]
1078
- when object == 'params' then _origin.params[var_name]
1079
- when object == 'site' then _origin.dc_get_site.send(var_name)
1080
- when object == 'page' then _origin.page.send(var_name)
1081
- when object == 'record' then
1075
+ case object
1076
+ when 'session' then _origin.session[var_name]
1077
+ when 'params' then _origin.params[var_name]
1078
+ when 'site' then _origin.dc_get_site.send(var_name)
1079
+ when 'page' then _origin.page.send(var_name)
1080
+ when 'record' then
1082
1081
  current_document ? current_document.send(var_name) : _origin.record.send(var_name)
1083
- when object == 'class' then
1082
+ when 'class' then
1084
1083
  clas, method_name = var_name.split('.')
1085
1084
  klas = clas.classify.constantize
1086
1085
  # call method. Error will be caught below.
1087
1086
  klas.send(method_name)
1088
1087
  else
1089
- 'VARIABLE: UNKNOWN OBJECT'
1088
+ 'dc_internal: UNKNOWN OBJECT'
1090
1089
  end
1091
1090
  rescue Exception => e
1092
1091
  Rails.logger.debug "\ndc_internal_var. Runtime error. #{e.message}\n"
1093
1092
  Rails.logger.debug(e.backtrace.join($/)) if Rails.env.development?
1094
- 'VARIABLE: ERROR'
1093
+ 'dc_internal: ERROR'
1095
1094
  end
1096
1095
  end
1097
1096
 
@@ -1119,14 +1118,13 @@ end
1119
1118
  # Returns:
1120
1119
  # HTML data to be embedded into page header
1121
1120
  #######################################################################
1122
- def dc_get_json_ld()
1123
- return '' if @json_ld.nil? or @json_ld.size == 0
1121
+ def dc_get_json_ld
1122
+ return '' if @json_ld.blank?
1124
1123
 
1125
- %Q[
1124
+ %(
1126
1125
  <script type="application/ld+json">
1127
- #{JSON.pretty_generate({'@context' => 'http://schema.org', '@graph' => @json_ld})}
1128
- </script>
1129
- ].html_safe
1126
+ #{JSON.pretty_generate({ '@context' => 'http://schema.org', '@graph' => @json_ld })}
1127
+ </script>).html_safe
1130
1128
  end
1131
1129
 
1132
1130
  ########################################################################
@@ -1145,21 +1143,40 @@ def dc_add_json_ld(element)
1145
1143
  end
1146
1144
 
1147
1145
  ########################################################################
1148
- # Will return meta data for SEO optimizations
1146
+ # Will return meta data for SEO optimizations.
1147
+ # It will also create special link rel="canonical" tag if defined in meta tags or page document.
1149
1148
  #
1150
1149
  # Returns:
1151
1150
  # HTML data to be embedded into page header
1152
1151
  #######################################################################
1153
- def dc_get_seo_meta_tags()
1152
+ def dc_get_seo_meta_tags
1154
1153
  html = ''
1155
- html << "<link rel=\"canonical\" href=\"#{@page.canonical_link}\">\n " unless @page&.canonical_link.blank?
1156
-
1157
- html << @meta_tags.inject('') do |r, hash|
1158
- r << "<meta #{hash.first} content=\"#{hash.last}\">\n "
1154
+ has_canonical = false
1155
+ html << @meta_tags.inject('') do |r, tag|
1156
+ r << if tag.first.match('canonical')
1157
+ has_canonical = true
1158
+ dc_get_link_canonical_tag(tag.last)
1159
+ else
1160
+ %(<meta #{tag.first} content="#{tag.last}">\n )
1161
+ end
1159
1162
  end if @meta_tags
1163
+ html << dc_get_link_canonical_tag(@page&.canonical_link) unless has_canonical
1160
1164
  html.html_safe
1161
1165
  end
1162
1166
 
1167
+ ########################################################################
1168
+ # helper for setting canonical link on the page
1169
+ #######################################################################
1170
+ def dc_get_link_canonical_tag(href = nil)
1171
+ return %(<link rel="canonical" href="#{request.url}">\n) if href.blank?
1172
+
1173
+ unless href.match(/^http/i)
1174
+ uri = URI.parse(request.url)
1175
+ href = "#{uri.scheme}://#{uri.host}/#{href.delete_prefix('/')}"
1176
+ end
1177
+ %(<link rel="canonical" href="#{href}">\n)
1178
+ end
1179
+
1163
1180
  ########################################################################
1164
1181
  # Will add a meta tag to internal hash structure. If meta tag already exists it
1165
1182
  # will be overwritten.
@@ -1170,6 +1187,7 @@ end
1170
1187
  ########################################################################
1171
1188
  def dc_add_meta_tag(type, name, content)
1172
1189
  return if content.blank?
1190
+
1173
1191
  @meta_tags ||= {}
1174
1192
  key = "#{type}=\"#{name}\""
1175
1193
  @meta_tags[key] = content
@@ -1187,8 +1205,8 @@ end
1187
1205
  # Returns:
1188
1206
  # [String] alt="image-tag"
1189
1207
  #######################################################################
1190
- def dc_img_alt_tag(file_name, text=nil)
1191
- " alt=\"#{dc_img_alt(file_name, text)}\" ".html_safe
1208
+ def dc_img_alt_tag(file_name, text = nil)
1209
+ %( alt="#{dc_img_alt(file_name, text)}" ).html_safe
1192
1210
  end
1193
1211
 
1194
1212
  #######################################################################
@@ -1203,15 +1221,19 @@ end
1203
1221
  # Returns:
1204
1222
  # [String] alt_image_name
1205
1223
  #######################################################################
1206
- def dc_img_alt(file_name, text=nil)
1207
- return text unless text.blank?
1224
+ def dc_img_alt(file_name, text = nil)
1225
+ return text if text.present?
1226
+
1208
1227
  name = File.basename(file_name.to_s)
1209
- name[0,name.index('.')].downcase rescue name
1228
+ name[0, name.index('.')].downcase rescue name
1210
1229
  end
1211
1230
 
1212
1231
  private
1213
1232
 
1214
- # will cache dc_user_can_view response
1233
+ ########################################################################
1234
+ # To cache localy dc_user_can_view response for a single call. It has large gains on sites
1235
+ # with large menus.
1236
+ ########################################################################
1215
1237
  def cache_add(id, can_view, msg)
1216
1238
  @can_view_cache[id] = [can_view, msg]
1217
1239
  end
@@ -0,0 +1,127 @@
1
+ #--
2
+ # Copyright (c) 2022+ Damjan Rems
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+
25
+ ####################################################################
26
+ # Helpers needed by some form fields
27
+ ####################################################################
28
+ module DcImageHelper
29
+
30
+ ############################################################################
31
+ # Will return code for previewing image on top of dc_image entry form
32
+ ############################################################################
33
+ def dc_image_preview(document, *parms)
34
+ src = "/#{dc_get_site.params.dig('dc_image', 'location')}/#{document.first_available_image}"
35
+ %(<span class="dc-image-preview dc-image-preview-1"><img src="#{src}"></img></span>).html_safe
36
+ end
37
+
38
+ ############################################################################
39
+ # Will return code for previewing resized images on dc_image entry form
40
+ ############################################################################
41
+ def dc_image_preview_resized(document, yaml, ignore)
42
+ size = yaml['name'].last
43
+ return '' if document["size_#{size}"].blank?
44
+
45
+ src = "/#{dc_get_site.params.dig('dc_image', 'location')}/#{document.id}-#{size}.#{document.img_type}?#{Time.now.to_i}"
46
+ %(<span class="dc-image-preview"><img src="#{src}"></img></span><div id="dc-image-preview"></div>).html_safe
47
+ end
48
+
49
+ ############################################################################
50
+ # Will return choices for preset image sizes
51
+ ############################################################################
52
+ def dc_image_choices_for_image_size
53
+ sizes = dc_get_site.params.dig('dc_image', 'sizes')
54
+ return ['300x200'] if sizes.blank?
55
+
56
+ sizes.split(",").map(&:strip)
57
+ end
58
+
59
+ ############################################################################
60
+ # Will return code for invoking dc_image_search form to select image select on a DRG Form.
61
+ #
62
+ # @param [String] field_name : Field name to which selected image value will be saved.
63
+ ###########################################################################
64
+ def dc_image_invoke(field_name)
65
+ return '' unless dc_get_site.params.dig('dc_image', 'location')
66
+
67
+ url = url_for(controller: :cmsedit, form_name: :dc_image_search, table: :dc_image, field_name: field_name)
68
+ %(<span class="dc-window-open" data-url="#{url}" title="#{t('drgcms.dc_image.invoke')}">#{mi_icon('image-o')}</span>).html_safe
69
+ end
70
+
71
+ ############################################################################
72
+ # Will return code for previewing image on top of dc_image entry form
73
+ ############################################################################
74
+ def first_dc_image(document, *parms)
75
+ src = "/#{dc_get_site.params.dig('dc_image', 'location')}/#{document.first_available_image}"
76
+ %(<span class="dc-image-preview"><img src="#{src}"></img></span><span id="dc-image-preview">).html_safe
77
+ end
78
+
79
+ ######################################################################
80
+ # Will format qry result as html code for selecting image
81
+ ######################################################################
82
+ def select_links_for_dc_image(doc, *parms)
83
+ %w[o s m l].inject('') { | r,size| r << dc_image_link_for_select(doc, size) }.html_safe
84
+ end
85
+
86
+ ######################################################################
87
+ # Will return HTML code for selecting image
88
+ ######################################################################
89
+ def dc_image_link_for_select(doc, what)
90
+ field = "size_#{what}"
91
+ value = doc.send(field)
92
+ return '' if value.blank?
93
+
94
+ value = value.split(/\+/).first
95
+ src = "/#{dc_get_site.params.dig('dc_image', 'location')}/#{doc.id}-#{what}.#{doc.img_type}"
96
+ %(
97
+ <div class="img-link"><div>
98
+ #{value}<br>
99
+ <i class="mi-o mi-preview" onclick="dc_image_preview('#{src}');" title="#{t('drgcms.dc_image.preview')}"></i>
100
+ <i class="mi-o mi-check_circle" onclick="dc_image_select('#{src}');" title="#{t('drgcms.dc_image.select')}"></i>
101
+ </div></div>)
102
+ end
103
+
104
+ ######################################################################
105
+ # Will return image file for requested size.
106
+ #
107
+ # @param [String] file_name : Image file name
108
+ # @param [String] size : Preferred image size
109
+ #
110
+ # @return [String] : Image file name if requested size is found. Otherwise first available image.
111
+ ######################################################################
112
+ def dc_image_get_by_size(file_name, size)
113
+ id = file_name[file_name.rindex('/') + 1, 24]
114
+ return 'error: ID not valid' unless BSON::ObjectId.legal?(id)
115
+
116
+ image = DcImage.find(id)
117
+ return 'error: ID not found' unless image
118
+
119
+ what = %w[o s m l].inject('l') do |r, e|
120
+ field_name = "size_#{e}".to_sym
121
+ break e if doc.send(field_name) == size
122
+ e
123
+ end
124
+ "/#{dc_get_site.params.dig('dc_image', 'location')}/#{doc.id}-#{what}.#{doc.img_type}"
125
+ end
126
+
127
+ end
@@ -52,7 +52,7 @@ after_destroy :cache_clear
52
52
  def self.values_for_permissions
53
53
  key = 'helpers.label.dc_policy_rule.choices4_permission'
54
54
  c = I18n.t(key)
55
- c = I18n.t(key, locale: 'en') if c.class == Hash or c.match( 'translation missing' )
55
+ c = I18n.t(key, locale: 'en') if c.class == Hash || c.match(/translation missing/i)
56
56
  c.split(',').inject([]) { |r,e| r << (ar = e.split(':'); [ar.first, ar.last.to_i]) }
57
57
  end
58
58
 
@@ -80,7 +80,7 @@ index group: 1
80
80
  validates_length_of :username, minimum: 4
81
81
  validates :username, uniqueness: true
82
82
  validates :email, uniqueness: true
83
- validate :do_validate
83
+ validate :additional_validates
84
84
 
85
85
  before_save :do_before_save
86
86
  before_validation :do_before_validation
@@ -97,8 +97,16 @@ def has_role?(role_id)
97
97
  role = DcPolicyRole.get_role(role_id)
98
98
  role_id = role.id if role
99
99
  end
100
- role = self.dc_user_roles.where(dc_policy_role_id: role_id).first
101
- (role && role.active)
100
+ role = dc_user_roles.find_by(dc_policy_role_id: role_id)
101
+
102
+ # user can be member of groups
103
+ if role.nil? && member.present?
104
+ member.each do |group_id|
105
+ role = DrgCms.cached(DcUser, group_id).dc_user_roles.find_by(dc_policy_role_id: role_id)
106
+ break if role
107
+ end
108
+ end
109
+ role&.active?
102
110
  end
103
111
 
104
112
  ##########################################################################
@@ -141,7 +149,7 @@ end
141
149
  # Will return list of available groups
142
150
  ##########################################################################
143
151
  def self.groups_for_select
144
- where(group: true, active: true).order_by(name: 1).inject([]) { |r, e| r << [e.name, e.id] }
152
+ where(group: true, active: true).order_by(name: 1).map { [_1.name, _1.id] }
145
153
  end
146
154
 
147
155
  private
@@ -169,7 +177,7 @@ end
169
177
  ##########################################################################
170
178
  # Perform some additional validations
171
179
  ##########################################################################
172
- def do_validate
180
+ def additional_validates
173
181
  if group && member.present?
174
182
  errors.add('member', I18n.t('errors.messages.present'))
175
183
  end
@@ -94,7 +94,7 @@ def self.choices4(key, site = nil, locale = nil)
94
94
  end
95
95
  # Error if empty
96
96
  result = [[I18n.t('drgcms.error'),I18n.t('drgcms.error')]] if result.size == 0
97
- result
97
+ result.sort_alphabetical_by(&:first)
98
98
  end
99
99
 
100
100
  end
@@ -63,6 +63,16 @@ validates :name, presence: true
63
63
 
64
64
  before_destroy :can_destroy?
65
65
 
66
+ after_save :cache_clear
67
+ after_destroy :cache_clear
68
+
69
+ ####################################################################
70
+ # Clear cache if cache is configured
71
+ ####################################################################
72
+ def cache_clear
73
+ DrgCms.cache_clear(:dc_category)
74
+ end
75
+
66
76
  private
67
77
 
68
78
  #########################################################################
@@ -88,6 +98,8 @@ def self.values_for_parent(site_id = nil) #:nodoc:
88
98
  parent = v.parent
89
99
  until parent.nil?
90
100
  doc = find(parent)
101
+ break if doc.nil?
102
+
91
103
  name = doc.name + ' / ' + name
92
104
  parent = doc.parent
93
105
  end
@@ -124,10 +124,11 @@ end
124
124
  # have site assigned will be selected. Too much designs to select often confuses
125
125
  # end user.
126
126
  ########################################################################
127
- def self.choices4_design(site=nil)
128
- list = site.nil? ? where(active: true) : where(active: true).in(site_id: [nil,site.id]).to_a
129
- list.sort! { |w1, w2| w1.description.casecmp(w2.description) }
130
- list.inject([]) { |r, design| r << [ design.description, design._id] }
127
+ def self.choices4_design(site)
128
+ (site.blank? ? where(active: true) : where(:site_id.in => [nil, BSON::ObjectId.from_string(site) ], active: true))
129
+ .only(:id, :description)
130
+ .order_by(description: 1)
131
+ .map { |design| [design.description, design.id] }
131
132
  end
132
133
 
133
134
  end